]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
people tag actions
authorShashi Gowda <connect2shashi@gmail.com>
Sun, 6 Mar 2011 19:13:31 +0000 (00:43 +0530)
committerShashi Gowda <connect2shashi@gmail.com>
Sun, 6 Mar 2011 19:13:31 +0000 (00:43 +0530)
23 files changed:
actions/addpeopletag.php [new file with mode: 0644]
actions/editpeopletag.php [new file with mode: 0644]
actions/peopletag.php
actions/peopletagautocomplete.php [new file with mode: 0644]
actions/peopletagged.php [new file with mode: 0644]
actions/peopletagsbyuser.php [new file with mode: 0644]
actions/peopletagsforuser.php [new file with mode: 0644]
actions/peopletagsubscribers.php [new file with mode: 0644]
actions/peopletagsubscriptions.php [new file with mode: 0644]
actions/profilecompletion.php [new file with mode: 0644]
actions/profilesettings.php
actions/profiletagbyid.php [new file with mode: 0644]
actions/public.php
actions/publicpeopletagcloud.php [new file with mode: 0644]
actions/removepeopletag.php [new file with mode: 0644]
actions/selftag.php [new file with mode: 0644]
actions/showprofiletag.php [new file with mode: 0644]
actions/subscribepeopletag.php [new file with mode: 0644]
actions/tagother.php [deleted file]
actions/tagprofile.php [new file with mode: 0644]
actions/unsubscribepeopletag.php [new file with mode: 0644]
lib/action.php
lib/router.php

diff --git a/actions/addpeopletag.php b/actions/addpeopletag.php
new file mode 100644 (file)
index 0000000..3176a11
--- /dev/null
@@ -0,0 +1,172 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2010, StatusNet, Inc.
+ *
+ * Action to add a people tag to a user.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR . '/lib/togglepeopletag.php';
+
+/**
+ *  
+ * Action to tag a profile with a single tag.
+ * 
+ * Takes parameters:
+ *
+ *    - tagged: the ID of the profile being tagged
+ *    - token: session token to prevent CSRF attacks
+ *    - ajax: boolean; whether to return Ajax or full-browser results
+ *    - peopletag_id: the ID of the tag being used
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+class AddpeopletagAction extends Action
+{
+    var $user;
+    var $tagged;
+    var $peopletag;
+
+    /**
+     * Check pre-requisites and instantiate attributes
+     *
+     * @param Array $args array of arguments (URL, GET, POST)
+     *
+     * @return boolean success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        // CSRF protection
+
+        $token = $this->trimmed('token');
+
+        if (!$token || $token != common_session_token()) {
+            $this->clientError(_('There was a problem with your session token.'.
+                                 ' Try again, please.'));
+            return false;
+        }
+
+        // Only for logged-in users
+
+        $this->user = common_current_user();
+
+        if (empty($this->user)) {
+            $this->clientError(_('Not logged in.'));
+            return false;
+        }
+
+        // Profile to subscribe to
+
+        $tagged_id = $this->arg('tagged');
+
+        $this->tagged = Profile::staticGet('id', $tagged_id);
+
+        if (empty($this->tagged)) {
+            $this->clientError(_('No such profile.'));
+            return false;
+        }
+
+        $id = $this->arg('peopletag_id');
+        $this->peopletag = Profile_list::staticGet('id', $id);
+
+        if (empty($this->peopletag)) {
+            $this->clientError(_('No such peopletag.'));
+            return false;
+        }
+
+        // OMB 0.1 doesn't have a mechanism for local-server-
+        // originated tag.
+
+        $omb01 = Remote_profile::staticGet('id', $tagged_id);
+
+        if (!empty($omb01)) {
+            $this->clientError(_('You cannot tag an OMB 0.1'.
+                                 ' remote profile with this action.'));
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Handle request
+     *
+     * Does the tagging and returns results.
+     *
+     * @param Array $args unused.
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+
+        // Throws exception on error
+        $ptag = Profile_tag::setTag($this->user->id, $this->tagged->id,
+                                $this->peopletag->tag);
+
+        if (!$ptag) {
+            $user = User::staticGet('id', $id);
+            if ($user) {
+                $this->clientError(
+                        sprintf(_('There was an unexpected error while tagging %s'),
+                        $user->nickname));
+            } else {
+                $this->clientError(sprintf(_('There was a problem tagging %s.' .
+                                      'The remote server is probably not responding correctly, ' .
+                                      'please try retrying later.'), $this->profile->profileurl));
+            }
+            return false;
+        }
+        if ($this->boolean('ajax')) {
+            $this->startHTML('text/xml;charset=utf-8');
+            $this->elementStart('head');
+            $this->element('title', null, _('Subscribed'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $unsubscribe = new UntagButton($this, $this->tagged, $this->peopletag);
+            $unsubscribe->show();
+            $this->elementEnd('body');
+            $this->elementEnd('html');
+        } else {
+            $url = common_local_url('subscriptions',
+                                    array('nickname' => $this->user->nickname));
+            common_redirect($url, 303);
+        }
+    }
+}
diff --git a/actions/editpeopletag.php b/actions/editpeopletag.php
new file mode 100644 (file)
index 0000000..b00ccc8
--- /dev/null
@@ -0,0 +1,311 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Edit an existing group
+ *
+ * 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  Group
+ * @package   StatusNet
+ * @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);
+}
+
+/**
+ * Add a new group
+ *
+ * This is the form for adding a new group
+ *
+ * @category Group
+ * @package  StatusNet
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class EditpeopletagAction extends OwnerDesignAction
+{
+
+    var $msg, $confirm, $confirm_args=array();
+
+    function title()
+    {
+        if ($_SERVER['REQUEST_METHOD'] == 'POST' && $this->boolean('delete')) {
+            return sprintf(_('Delete %s people tag'), $this->peopletag->tag);
+        }
+        return sprintf(_('Edit people tag %s'), $this->peopletag->tag);
+    }
+
+    /**
+     * Prepare to run
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        if (!common_logged_in()) {
+            $this->clientError(_('Not logged in.'));
+            return false;
+        }
+
+        $id = $this->arg('id');
+        $tagger_arg = $this->arg('tagger');
+        $tag_arg = $this->arg('tag');
+
+        $tagger = common_canonical_nickname($tagger_arg);
+        $tag = common_canonical_tag($tag_arg);
+
+        $current = common_current_user();
+
+        // Permanent redirect on non-canonical tag
+
+        if ($tagger_arg != $tagger || $tag_arg != $tag) {
+            $args = array('tagger' => $tagger, 'tag' => $tag);
+            common_redirect(common_local_url('editpeopletag', $args), 301);
+            return false;
+        }
+
+        $user = null;
+        if ($id) {
+            $this->peopletag = Profile_list::staticGet('id', $id);
+            if (!empty($this->peopletag)) {
+                $user = User::staticGet('id', $this->peopletag->tagger);
+            }
+        } else {
+            if (!$tagger) {
+                $this->clientError(_('No tagger or ID.'), 404);
+                return false;
+            }
+
+            $user = User::staticGet('nickname', $tagger);
+            $this->peopletag = Profile_list::pkeyGet(array('tagger' => $user->id, 'tag' => $tag));
+        }
+
+        if (!$this->peopletag) {
+            $this->clientError(_('No such peopletag.'), 404);
+            return false;
+        }
+
+        if (!$user) {
+            // This should not be happening
+            $this->clientError(_('Not a local user.'), 404);
+            return false;
+        }
+
+        if ($current->id != $user->id) {
+            $this->clientError(_('You must be the creator of the tag to edit it.'), 404);
+            return false;
+        }
+
+        $this->tagger = $user->getProfile();
+
+        return true;
+    }
+
+    /**
+     * Handle the request
+     *
+     * On GET, show the form. On POST, try to save the group.
+     *
+     * @param array $args unused
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        parent::handle($args);
+        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+            $this->trySave();
+        } else {
+            $this->showForm();
+        }
+    }
+
+    function showConfirm($msg=null, $fwd=null)
+    {
+        $this->confirm = $msg;
+        $this->confirm_args = $fwd;
+        $this->showPage();
+    }
+
+    function showConfirmForm()
+    {
+        $this->elementStart('form', array('id' => 'form_peopletag_edit_confirm',
+                                          'class' => 'form_settings',
+                                          'method' => 'post',
+                                          'action' => common_local_url('editpeopletag',
+                                              array('tagger' => $this->tagger->nickname,
+                                                    'tag' => $this->peopletag->tag))));
+        $this->elementStart('fieldset');
+        $this->hidden('token', common_session_token());
+        $this->hidden('id', $this->arg('id'));
+
+        foreach ($this->confirm_args as $key => $val) {
+            $this->hidden($key, $val);
+        }
+
+        $this->submit('form_action-no',
+                      _m('BUTTON','No'),
+                      'submit form_action-primary',
+                      'cancel');
+        $this->submit('form_action-yes',
+                      _m('BUTTON','Yes'),
+                      'submit form_action-secondary',
+                      'confirm');
+        $this->elementEnd('fieldset');
+        $this->elementEnd('form');
+    }
+
+    function showForm($msg=null)
+    {
+        $this->msg = $msg;
+        $this->showPage();
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PeopletagGroupNav($this, $this->peopletag);
+        $nav->show();
+    }
+
+    function showContent()
+    {
+        if ($this->confirm) {
+            $this->showConfirmForm();
+            return;
+        }
+
+        $form = new PeopletagEditForm($this, $this->peopletag);
+        $form->show();
+
+        $form->showProfileList();
+    }
+
+    function showPageNotice()
+    {
+        if ($this->msg) {
+            $this->element('p', 'error', $this->msg);
+        } else if ($this->confirm) {
+            $this->element('p', 'instructions', $this->confirm);
+        } else {
+            $this->element('p', 'instructions',
+                           _('Use this form to edit the people tag.'));
+        }
+    }
+
+    function showScripts()
+    {
+        parent::showScripts();
+        $this->autofocus('tag');
+    }
+
+    function trySave()
+    {
+        $tag         = common_canonical_tag($this->trimmed('tag'));
+        $description = $this->trimmed('description');
+        $private     = $this->boolean('private');
+        $delete      = $this->arg('delete');
+        $confirm     = $this->arg('confirm');
+        $cancel      = $this->arg('cancel');
+
+        if ($delete && $cancel) {
+            $this->showForm(_('Delete aborted.'));
+            return;
+        }
+
+        $set_private = $private && $this->peopletag->private != $private;
+
+        if ($delete && !$confirm) {
+            $this->showConfirm(_('Deleting this tag will permanantly remove ' .
+                                 'all its subscription and membership records. ' .
+                                 'Do you still want to continue?'), array('delete' => 1));
+            return;
+        } else if (common_valid_tag($tag)) {
+            $this->showForm(_('Invalid tag.'));
+            return;
+        } else if ($tag != $this->peopletag->tag && $this->tagExists($tag)) {
+            $this->showForm(sprintf(_('You already have a tag named %s.'), $tag));
+            return;
+        } else if (Profile_list::descriptionTooLong($description)) {
+            $this->showForm(sprintf(_('description is too long (max %d chars).'), Profile_list::maxDescription()));
+            return;
+        } else if ($set_private && !$confirm && !$cancel) {
+            $fwd = array('tag' => $tag,
+                         'description' => $description,
+                         'private' => (int) $private);
+
+            $this->showConfirm(_('Setting a public tag as private will ' .
+                                 'permanently remove all the existing ' .
+                                 'subscriptions to it. Do you still want to continue?'), $fwd);
+            return;
+        }
+
+        $this->peopletag->query('BEGIN');
+
+        $orig = clone($this->peopletag);
+
+        $this->peopletag->tag         = $tag;
+        $this->peopletag->description = $description;
+        if (!$set_private || $confirm) {
+            $this->peopletag->private     = $private;
+        }
+
+        $result = $this->peopletag->update($orig);
+
+        if (!$result) {
+            common_log_db_error($this->group, 'UPDATE', __FILE__);
+            $this->serverError(_('Could not update peopletag.'));
+        }
+
+        $this->peopletag->query('COMMIT');
+
+        if ($set_private && $confirm) {
+            Profile_tag_subscription::cleanup($this->peopletag);
+        }
+
+        if ($delete) {
+            // This might take quite a bit of time.
+            $this->peopletag->delete();
+            // send home.
+            common_redirect(common_local_url('all',
+                                         array('nickname' => $this->tagger->nickname)),
+                            303);
+        }
+
+        if ($tag != $orig->tag) {
+            common_redirect(common_local_url('editpeopletag',
+                                             array('tagger' => $this->tagger->nickname,
+                                                   'tag'    => $tag)),
+                            303);
+        } else {
+            $this->showForm(_('Options saved.'));
+        }
+    }
+
+    function tagExists($tag)
+    {
+        $args = array('tagger' => $this->tagger->id, 'tag' => $tag);
+        $ptag = Profile_list::pkeyGet($args);
+
+        return !empty($ptag);
+    }
+}
index 7287cfbf995aa0bf08d29df44cde7627ff59f87b..d549586f13df1bdf1ffbbe366686c247da3d47ea 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * StatusNet, the distributed open-source microblogging tool
  *
- * Action for showing profiles self-tagged with a given tag
+ * People tags by a user
  *
  * PHP version 5
  *
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Affero General Public License for more details.
  *
+ * PHP version 5
+ *
  * 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
+ * @category  Personal
  * @package   StatusNet
  * @author    Evan Prodromou <evan@status.net>
  * @author    Zach Copley <zach@status.net>
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
  * @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/
@@ -32,149 +35,125 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
     exit(1);
 }
 
-/**
- * This class outputs a paginated list of profiles self-tagged with a given tag
- *
- * @category Output
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @author   Zach Copley <zach@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Action
- */
+require_once INSTALLDIR.'/lib/peopletaglist.php';
+// cache 3 pages
+define('PEOPLETAG_CACHE_WINDOW', PEOPLETAGS_PER_PAGE*3 + 1);
 
 class PeopletagAction extends Action
 {
-
-    var $tag  = null;
     var $page = null;
+    var $tag = null;
 
-    /**
-     * For initializing members of the class.
-     *
-     * @param array $argarray misc. arguments
-     *
-     * @return boolean true
-     */
-    function prepare($argarray)
+    function isReadOnly($args)
     {
-        parent::prepare($argarray);
-
-        $this->tag = $this->trimmed('tag');
-
-        if (!common_valid_profile_tag($this->tag)) {
-            $this->clientError(sprintf(_('Not a valid people tag: %s.'),
-                $this->tag));
-            return;
-        }
-
-        $this->page = ($this->arg('page')) ? $this->arg('page') : 1;
-
-        common_set_returnto($this->selfUrl());
-
         return true;
     }
 
-    /**
-     * Handler method
-     *
-     * @param array $argarray is ignored since it's now passed in in prepare()
-     *
-     * @return boolean is read only action?
-     */
-    function handle($argarray)
+    function title()
     {
-        parent::handle($argarray);
-        $this->showPage();
+        if ($this->page == 1) {
+            return sprintf(_("Public people tag %s"), $this->tag);
+        } else {
+            return sprintf(_("Public people tag %s, page %d"), $this->tag, $this->page);
+        }
     }
 
-    /**
-     * Whips up a query to get a list of profiles based on the provided
-     * people tag and page, initalizes a ProfileList widget, and displays
-     * it to the user.
-     *
-     * @return nothing
-     */
-    function showContent()
+    function prepare($args)
     {
+        parent::prepare($args);
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
 
-        $profile = new Profile();
+        $tag_arg = $this->arg('tag');
+        $tag = common_canonical_tag($tag_arg);
 
-        $offset = ($this->page - 1) * PROFILES_PER_PAGE;
-        $limit  = PROFILES_PER_PAGE + 1;
+        // Permanent redirect on non-canonical nickname
 
-        if (common_config('db', 'type') == 'pgsql') {
-            $lim = ' LIMIT ' . $limit . ' OFFSET ' . $offset;
-        } else {
-            $lim = ' LIMIT ' . $offset . ', ' . $limit;
+        if ($tag_arg != $tag) {
+            $args = array('tag' => $nickname);
+            if ($this->page && $this->page != 1) {
+                $args['page'] = $this->page;
+            }
+            common_redirect(common_local_url('peopletag', $args), 301);
+            return false;
         }
+        $this->tag = $tag;
 
-        // XXX: memcached this
-
-        $qry =  'SELECT profile.* ' .
-                'FROM profile JOIN profile_tag ' .
-                'ON profile.id = profile_tag.tagger ' .
-                'WHERE profile_tag.tagger = profile_tag.tagged ' .
-                "AND tag = '%s' " .
-                'ORDER BY profile_tag.modified DESC%s';
-
-        $profile->query(sprintf($qry, $this->tag, $lim));
-
-        $ptl = new PeopleTagList($profile, $this); // pass the ammunition
-        $cnt = $ptl->show();
-
-        $this->pagination($this->page > 1,
-                          $cnt > PROFILES_PER_PAGE,
-                          $this->page,
-                          'peopletag',
-                          array('tag' => $this->tag));
+        return true;
     }
 
-    /**
-     * Returns the page title
-     *
-     * @return string page title
-     */
-    function title()
+    function handle($args)
     {
-        return sprintf(_('Users self-tagged with %1$s - page %2$d'),
-            $this->tag, $this->page);
+        parent::handle($args);
+        $this->showPage();
     }
 
-}
+    function showLocalNav()
+    {
+        $nav = new PublicGroupNav($this);
+        $nav->show();
+    }
 
-class PeopleTagList extends ProfileList
-{
-    function newListItem($profile)
+    function showAnonymousMessage()
     {
-        return new PeopleTagListItem($profile, $this->action);
+        $notice =
+          _('People tags are how you sort similar ' .
+            'people on %%site.name%%, a [micro-blogging]' .
+            '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
+            'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+            'You can then easily keep track of what they ' .
+            'are doing by subscribing to the tag\'s timeline.' );
+        $this->elementStart('div', array('id' => 'anon_notice'));
+        $this->raw(common_markup_to_html($notice));
+        $this->elementEnd('div');
     }
-}
 
-class PeopleTagListItem extends ProfileListItem
-{
-    function linkAttributes()
+    function showContent()
     {
-        $aAttrs = parent::linkAttributes();
+        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
+        $limit  = PEOPLETAGS_PER_PAGE + 1;
+
+        $ptags = new Profile_list();
+        $ptags->tag = $this->tag;
+
+        $user = common_current_user();
+
+        if (empty($user)) {
+            $ckey = sprintf('profile_list:tag:%s', $this->tag);
+            $ptags->private = false;
+            $ptags->orderBy('profile_list.modified DESC');
+
+            $c = Cache::instance();
+            if ($offset+$limit <= PEOPLETAG_CACHE_WINDOW && !empty($c)) {
+                $cached_ptags = Profile_list::getCached($ckey, $offset, $limit);
+                if ($cached_ptags === false) {
+                    $ptags->limit(0, PEOPLETAG_CACHE_WINDOW);
+                    $ptags->find();
+
+                    Profile_list::setCache($ckey, $ptags, $offset, $limit);
+                } else {
+                    $ptags = clone($cached_ptags);
+                }
+            } else {
+                $ptags->limit($offset, $limit);
+                $ptags->find();
+            }
+        } else {
+            $ptags->whereAdd('(profile_list.private = false OR (' .
+                             ' profile_list.tagger =' . $user->id .
+                             ' AND profile_list.private = true) )');   
 
-        if (common_config('nofollow', 'peopletag')) {
-            $aAttrs['rel'] .= ' nofollow';
+            $ptags->orderBy('profile_list.modified DESC');
+            $ptags->find();
         }
 
-        return $aAttrs;
+        $pl = new PeopletagList($ptags, $this);
+        $cnt = $pl->show();
+
+        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
+                          $this->page, 'peopletag', array('tag' => $this->tag));
     }
 
-    function homepageAttributes()
+    function showSections()
     {
-        $aAttrs = parent::linkAttributes();
-
-        if (common_config('nofollow', 'peopletag')) {
-            $aAttrs['rel'] = 'nofollow';
-        }
-
-        return $aAttrs;
     }
 }
-
diff --git a/actions/peopletagautocomplete.php b/actions/peopletagautocomplete.php
new file mode 100644 (file)
index 0000000..db11a24
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2010, StatusNet, Inc.
+ *
+ * Peopletag autocomple action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+class PeopletagautocompleteAction extends Action
+{
+    var $user;
+
+    /**
+     * Check pre-requisites and instantiate attributes
+     *
+     * @param Array $args array of arguments (URL, GET, POST)
+     *
+     * @return boolean success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        // Only for logged-in users
+
+        $this->user = common_current_user();
+
+        if (empty($this->user)) {
+            $this->clientError(_('Not logged in.'));
+            return false;
+        }
+
+        // CSRF protection
+
+        $token = $this->trimmed('token');
+
+        if (!$token || $token != common_session_token()) {
+            $this->clientError(_('There was a problem with your session token.'.
+                                 ' Try again, please.'));
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Handle request
+     *
+     * Does the subscription and returns results.
+     *
+     * @param Array $args unused.
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        $profile = $this->user->getProfile();
+        $tags = $profile->getOwnedTags(common_current_user());
+
+        $tags_array = array();
+        while ($tags->fetch()) {
+            $arr = array();
+            $arr['tag'] = $tags->tag;
+            $arr['mode'] = $tags->private ? 'private' : 'public';
+            // $arr['url'] = $tags->homeUrl();
+            $arr['freq'] = $tags->taggedCount();
+
+            $tags_array[] = $arr;
+        }
+
+        $tags->free();
+
+        //common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($tags_array));
+        print(json_encode($tags_array));
+        exit(0);
+    }
+}
diff --git a/actions/peopletagged.php b/actions/peopletagged.php
new file mode 100644 (file)
index 0000000..5038d1e
--- /dev/null
@@ -0,0 +1,223 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of people tagged by the user with a tag
+ *
+ * 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  Group
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @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/profilelist.php');
+
+/**
+ * List of people tagged by the user with a tag
+ *
+ * @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 PeopletaggedAction extends OwnerDesignAction
+{
+    var $page = null;
+    var $peopletag = null;
+    var $tagger = null;
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+        $tagger_arg = $this->arg('tagger');
+        $tag_arg = $this->arg('tag');
+        $tagger = common_canonical_nickname($tagger_arg);
+        $tag = common_canonical_tag($tag_arg);
+
+        // Permanent redirect on non-canonical nickname
+
+        if ($tagger_arg != $tagger || $tag_arg != $tag) {
+            $args = array('tagger' => $nickname, 'tag' => $tag);
+            if ($this->page != 1) {
+                $args['page'] = $this->page;
+            }
+            common_redirect(common_local_url('peopletagged', $args), 301);
+            return false;
+        }
+
+        if (!$tagger) {
+            $this->clientError(_('No tagger.'), 404);
+            return false;
+        }
+
+        $user = User::staticGet('nickname', $tagger);
+
+        if (!$user) {
+            $this->clientError(_('No such user.'), 404);
+            return false;
+        }
+
+        $this->tagger = $user->getProfile();
+        $this->peopletag = Profile_list::pkeyGet(array('tagger' => $user->id, 'tag' => $tag));
+
+        if (!$this->peopletag) {
+            $this->clientError(_('No such peopletag.'), 404);
+            return false;
+        }
+
+        return true;
+    }
+
+    function title()
+    {
+        if ($this->page == 1) {
+            return sprintf(_('People tagged %s by %s'),
+                           $this->peopletag->tag, $this->tagger->nickname);
+        } else {
+            return sprintf(_('People tagged %s by %s, page %d'),
+                           $this->peopletag->tag, $this->user->nickname,
+                           $this->page);
+        }
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    function showPageNotice()
+    {
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PeopletagGroupNav($this, $this->peopletag);
+        $nav->show();
+    }
+
+    function showContent()
+    {
+        $offset = ($this->page-1) * PROFILES_PER_PAGE;
+        $limit =  PROFILES_PER_PAGE + 1;
+
+        $cnt = 0;
+
+        $subs = $this->peopletag->getTagged($offset, $limit);
+
+        if ($subs) {
+            $subscriber_list = new PeopletagMemberList($subs, $this->peopletag, $this);
+            $cnt = $subscriber_list->show();
+        }
+
+        $subs->free();
+
+        $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
+                          $this->page, 'peopletagged',
+                          array('tagger' => $this->tagger->nickname,
+                                'tag'    => $this->peopletag->tag));
+    }
+}
+
+class PeopletagMemberList extends ProfileList
+{
+    var $peopletag = null;
+
+    function __construct($profile, $peopletag, $action)
+    {
+        parent::__construct($profile, $action);
+
+        $this->peopletag = $peopletag;
+    }
+
+    function newListItem($profile)
+    {
+        return new PeopletagMemberListItem($profile, $this->peopletag, $this->action);
+    }
+}
+
+class PeopletagMemberListItem extends ProfileListItem
+{
+    var $peopletag = null;
+
+    function __construct($profile, $peopletag, $action)
+    {
+        parent::__construct($profile, $action);
+
+        $this->peopletag = $peopletag;
+    }
+
+    function showFullName()
+    {
+        parent::showFullName();
+        if ($this->profile->id == $this->peopletag->tagger) {
+            $this->out->text(' ');
+            $this->out->element('span', 'role', _('Creator'));
+        }
+    }
+
+    function showActions()
+    {
+        $this->startActions();
+        if (Event::handle('StartProfileListItemActionElements', array($this))) {
+            $this->showSubscribeButton();
+            // TODO: Untag button
+            Event::handle('EndProfileListItemActionElements', array($this));
+        }
+        $this->endActions();
+    }
+
+    function linkAttributes()
+    {
+        // tagging people is healthy page-rank flow.
+        return parent::linkAttributes();
+    }
+
+    /**
+     * Fetch necessary return-to arguments for the profile forms
+     * to return to this list when they're done.
+     * 
+     * @return array
+     */
+    protected function returnToArgs()
+    {
+        $args = array('action' => 'peopletagged',
+                      'tag' => $this->peopletag->tag,
+                      'tagger' => $this->profile->nickname);
+        $page = $this->out->arg('page');
+        if ($page) {
+            $args['param-page'] = $page;
+        }
+        return $args;
+    }
+}
diff --git a/actions/peopletagsbyuser.php b/actions/peopletagsbyuser.php
new file mode 100644 (file)
index 0000000..3158b71
--- /dev/null
@@ -0,0 +1,258 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * People tags by 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  Personal
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @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/peopletaglist.php';
+
+class PeopletagsbyuserAction extends OwnerDesignAction
+{
+    var $page = null;
+    var $tagger = null;
+    var $tags = null;
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function title()
+    {
+        if ($this->page == 1) {
+            if ($this->isOwner()) {
+                if ($this->arg('private')) {
+                    return _('Private people tags by you');
+                } else if ($this->arg('public')) {
+                    return _('Public people tags by you');
+                }
+                return _('People tags by you');
+            }
+            return sprintf(_("People tags by %s"), $this->tagger->nickname);
+        } else {
+            return sprintf(_("People tags by %s, page %d"), $this->tagger->nickname, $this->page);
+        }
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        if ($this->arg('public') && $this->arg('private')) {
+            $this->args['public'] = $this->args['private'] = false;
+        }
+
+        $nickname_arg = $this->arg('nickname');
+        $nickname = common_canonical_nickname($nickname_arg);
+
+        // Permanent redirect on non-canonical nickname
+
+        if ($nickname_arg != $nickname) {
+            $args = $this->getSelfUrlArgs();
+            if ($this->arg('page') && $this->arg('page') != 1) {
+                $args['page'] = $this->arg['page'];
+            }
+            common_redirect(common_local_url('peopletagsbyuser', $args), 301);
+            return false;
+        }
+
+        $this->user = User::staticGet('nickname', $nickname);
+
+        if (!$this->user) {
+            $this->clientError(_('No such user.'), 404);
+            return false;
+        }
+
+        $this->tagger = $this->user->getProfile();
+
+        if (!$this->tagger) {
+            $this->serverError(_('User has no profile.'));
+            return false;
+        }
+
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+
+        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
+        $limit  = PEOPLETAGS_PER_PAGE + 1;
+
+        $user = common_current_user();
+        if ($this->arg('public')) {
+            $this->tags = $this->tagger->getOwnedTags(false, $offset, $limit);
+        } else if ($this->arg('private')) {
+            if (empty($user)) {
+                $this->clientError(_('Not logged in'), 403);
+            }
+
+            if ($this->isOwner()) {
+                $this->tags = $this->tagger->getPrivateTags($offset, $limit);
+            } else {
+                $this->clientError(_('You cannot view others\' private people tags'), 403);
+            }
+        } else {
+            $this->tags = $this->tagger->getOwnedTags(common_current_user(), $offset, $limit);
+        }
+        return true;
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+
+               # Post from the tag dropdown; redirect to a GET
+
+               if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+                   common_redirect(common_local_url('peopletagsbyuser', $this->getSelfUrlArgs()), 303);
+            return;
+               }
+
+        $this->showPage();
+    }
+
+    function showModeSelector()
+    {
+        $this->elementStart('dl', array('id'=>'filter_tags'));
+        $this->element('dt', null, _('Mode'));
+        $this->elementStart('dd');
+        $this->elementStart('ul');
+        $this->elementStart('li', array('id' => 'filter_tags_for',
+                                         'class' => 'child_1'));
+        $this->element('a',
+                       array('href' =>
+                             common_local_url('peopletagsforuser',
+                                              array('nickname' => $this->user->nickname))),
+                       sprintf(_('People tags for %s'), $this->tagger->nickname));
+        $this->elementEnd('li');
+
+        if ($this->isOwner()) {
+            $this->elementStart('li', array('id'=>'filter_tags_item'));
+            $this->elementStart('form', array('name' => 'modeselector',
+                                               'id' => 'form_filter_bymode',
+                                               'action' => common_local_url('peopletagsbyuser',
+                                                    array('nickname' => $this->tagger->nickname)),
+                                               'method' => 'post'));
+            $this->elementStart('fieldset');
+            $this->element('legend', null, _('Select tag to filter'));
+
+            $priv = $this->arg('private');
+            $pub  = $this->arg('public');
+
+            if (!$priv && !$pub) {
+                $priv = $pub = true;
+            }
+            $this->checkbox('private', _m('Private'), $priv,
+                                _m('Show private tags'));
+            $this->checkbox('public', _m('Public'), $pub,
+                                _m('Show public tags'));
+            $this->hidden('nickname', $this->user->nickname);
+            $this->submit('submit', _('Go'));
+            $this->elementEnd('fieldset');
+            $this->elementEnd('form');
+            $this->elementEnd('li');
+        }
+        $this->elementEnd('ul');
+        $this->elementEnd('dd');
+        $this->elementEnd('dl');
+    }
+    function showLocalNav()
+    {
+        $nav = new PersonalGroupNav($this);
+        $nav->show();
+    }
+
+    function showAnonymousMessage()
+    {
+        $notice =
+          sprintf(_('These are people tags created by **%s**. ' .
+                    'People tags are how you sort similar ' .
+                    'people on %%%%site.name%%%%, a [micro-blogging]' .
+                    '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
+                    'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+                    'You can easily keep track of what they ' .
+                    'are doing by subscribing to the tag\'s timeline.' ), $this->tagger->nickname);
+        $this->elementStart('div', array('id' => 'anon_notice'));
+        $this->raw(common_markup_to_html($notice));
+        $this->elementEnd('div');
+    }
+
+    function showPageNotice()
+    {
+        $this->elementStart('div', 'instructions');
+        $this->showModeSelector();
+        $this->elementEnd('div');
+    }
+
+    function showContent()
+    {
+        #TODO: controls here.
+
+        $pl = new PeopletagList($this->tags, $this);
+        $cnt = $pl->show();
+
+        if ($cnt == 0) {
+            $this->showEmptyListMessage();
+        }
+        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
+                          $this->page, 'peopletagsbyuser', $this->getSelfUrlArgs());
+    }
+
+    function getSelfUrlArgs()
+    {
+        $args = array();
+        if ($this->arg('private')) {
+            $args['private'] = 1;
+        } else if ($this->arg('public')) {
+            $args['public'] = 1;
+        }
+        $args['nickname'] = $this->trimmed('nickname');
+
+        return $args;
+    }
+
+    function isOwner()
+    {
+        $user = common_current_user();
+        return !empty($user) && $user->id == $this->tagger->id;
+    }
+
+    function showEmptyListMessage()
+    {
+        $message = sprintf(_('%s has not created any [people tags](%%%%doc.tags%%%%) yet.'), $this->tagger->nickname);
+        $this->elementStart('div', 'guide');
+        $this->raw(common_markup_to_html($message));
+        $this->elementEnd('div');
+    }
+
+    function showSections()
+    {
+        #TODO: tags with most subscribers
+        #TODO: tags with most "members"
+    }
+}
diff --git a/actions/peopletagsforuser.php b/actions/peopletagsforuser.php
new file mode 100644 (file)
index 0000000..b6875b3
--- /dev/null
@@ -0,0 +1,170 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * People tags for 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  Personal
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @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/peopletaglist.php';
+
+class PeopletagsforuserAction extends OwnerDesignAction
+{
+    var $page = null;
+    var $tagged = null;
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function title()
+    {
+        if ($this->page == 1) {
+            return sprintf(_("People tags for %s"), $this->tagged->nickname);
+        } else {
+            return sprintf(_("People tags for %s, page %d"), $this->tagged->nickname, $this->page);
+        }
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $nickname_arg = $this->arg('nickname');
+        $nickname = common_canonical_nickname($nickname_arg);
+
+        // Permanent redirect on non-canonical nickname
+
+        if ($nickname_arg != $nickname) {
+            $args = array('nickname' => $nickname);
+            if ($this->arg('page') && $this->arg('page') != 1) {
+                $args['page'] = $this->arg['page'];
+            }
+            common_redirect(common_local_url('peopletagsforuser', $args), 301);
+            return false;
+        }
+
+        $this->user = User::staticGet('nickname', $nickname);
+
+        if (!$this->user) {
+            $this->clientError(_('No such user.'), 404);
+            return false;
+        }
+
+        $this->tagged = $this->user->getProfile();
+
+        if (!$this->tagged) {
+            $this->serverError(_('User has no profile.'));
+            return false;
+        }
+
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+        return true;
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PersonalGroupNav($this);
+        $nav->show();
+    }
+
+    function showAnonymousMessage()
+    {
+        $notice =
+          sprintf(_('These are people tags for **%s**. ' .
+                    'People tags are how you sort similar ' .
+                    'people on %%%%site.name%%%%, a [micro-blogging]' .
+                    '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
+                    'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+                    'You can easily keep track of what they ' .
+                    'are doing by subscribing to the tag\'s timeline.' ), $this->tagged->nickname);
+        $this->elementStart('div', array('id' => 'anon_notice'));
+        $this->raw(common_markup_to_html($notice));
+        $this->elementEnd('div');
+    }
+
+    function showPageNotice()
+    {
+        $this->elementStart('dl', 'filter_tags');
+        $this->elementStart('dd', array('id' => 'filter_tags_for',
+                                         'class' => 'child_1'));
+
+        $user = common_current_user();
+        $text = ($this->tagged->id == @$user->id) ? _('People tags by you') :
+                sprintf(_('People tags by %s'), $this->tagged->nickname);
+        $this->element('a',
+                       array('href' =>
+                             common_local_url('peopletagsbyuser',
+                                              array('nickname' => $this->tagged->nickname))),
+                           $text);
+        $this->elementEnd('dd');
+        $this->elementEnd('dl');
+    }
+
+
+    function showContent()
+    {
+        #TODO: controls here.
+
+        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
+        $limit  = PEOPLETAGS_PER_PAGE + 1;
+
+        $ptags = $this->tagged->getOtherTags(common_current_user(), $offset, $limit);
+
+        $pl = new PeopletagList($ptags, $this);
+        $cnt = $pl->show();
+
+        if ($cnt == 0) {
+            $this->showEmptyListMessage();
+        }
+        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
+                          $this->page, 'peopletagsforuser', array('nickname' => $this->tagged->id));
+    }
+
+    function showEmptyListMessage()
+    {
+        $message = sprintf(_('%s has not been [tagged](%%%%doc.tags%%%%) by anyone yet.'), $this->tagged->nickname);
+        $this->elementStart('div', 'guide');
+        $this->raw(common_markup_to_html($message));
+        $this->elementEnd('div');
+    }
+
+    function showSections()
+    {
+        #TODO: tags with most subscribers
+        #TODO: tags with most "members"
+    }
+}
diff --git a/actions/peopletagsubscribers.php b/actions/peopletagsubscribers.php
new file mode 100644 (file)
index 0000000..1f2feec
--- /dev/null
@@ -0,0 +1,238 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of peopletag 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  Group
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+require_once(INSTALLDIR.'/lib/profilelist.php');
+
+/**
+ * List of peopletag subscribers
+ *
+ * @category Peopletag
+ * @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 PeopletagsubscribersAction extends OwnerDesignAction
+{
+    var $page = null;
+    var $peopletag = null;
+    var $tagger = null;
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+        $tagger_arg = $this->arg('tagger');
+        $tag_arg = $this->arg('tag');
+        $tagger = common_canonical_nickname($tagger_arg);
+        $tag = common_canonical_tag($tag_arg);
+
+        // Permanent redirect on non-canonical nickname
+
+        if ($tagger_arg != $tagger || $tag_arg != $tag) {
+            $args = array('tagger' => $nickname, 'tag' => $tag);
+            if ($this->page != 1) {
+                $args['page'] = $this->page;
+            }
+            common_redirect(common_local_url('peopletagged', $args), 301);
+            return false;
+        }
+
+        if (!$tagger) {
+            $this->clientError(_('No tagger.'), 404);
+            return false;
+        }
+
+        $user = User::staticGet('nickname', $tagger);
+
+        if (!$user) {
+            $this->clientError(_('No such user.'), 404);
+            return false;
+        }
+
+        $this->tagger = $user->getProfile();
+        $this->peopletag = Profile_list::pkeyGet(array('tagger' => $user->id, 'tag' => $tag));
+
+        if (!$this->peopletag) {
+            $this->clientError(_('No such peopletag.'), 404);
+            return false;
+        }
+
+        return true;
+    }
+
+    function title()
+    {
+        if ($this->page == 1) {
+            return sprintf(_('Subscribers of people tagged %s by %s'),
+                           $this->peopletag->tag, $this->tagger->nickname);
+        } else {
+            return sprintf(_('Subscribers of people tagged %s by %s, page %d'),
+                           $this->peopletag->tag, $this->tagger->nickname,
+                           $this->page);
+        }
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    function showPageNotice()
+    {
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PeopletagGroupNav($this);
+        $nav->show();
+    }
+
+    function showContent()
+    {
+        $offset = ($this->page-1) * PROFILES_PER_PAGE;
+        $limit =  PROFILES_PER_PAGE + 1;
+
+        $cnt = 0;
+
+        $subs = $this->peopletag->getSubscribers($offset, $limit);
+
+        if ($subs) {
+            $subscriber_list = new PeopletagSubscriberList($subs, $this->peopletag, $this);
+            $cnt = $subscriber_list->show();
+        }
+
+        $subs->free();
+
+        $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
+                          $this->page, 'peopletagsubscribers',
+                          array('tagger' => $this->tagger->nickname,
+                                'tag'    => $this->peopletag->tag));
+    }
+}
+
+class PeopletagSubscriberList extends ProfileList
+{
+    var $peopletag = null;
+
+    function __construct($profile, $peopletag, $action)
+    {
+        parent::__construct($profile, $action);
+
+        $this->peopletag = $peopletag;
+    }
+
+    function newListItem($profile)
+    {
+        return new PeopletagSubscriberListItem($profile, $this->peopletag, $this->action);
+    }
+}
+
+class PeopletagSubscriberListItem extends ProfileListItem
+{
+    var $peopletag = null;
+
+    function __construct($profile, $peopletag, $action)
+    {
+        parent::__construct($profile, $action);
+
+        $this->peopletag = $peopletag;
+    }
+
+    function showFullName()
+    {
+        parent::showFullName();
+        if ($this->profile->id == $this->peopletag->tagger) {
+            $this->out->text(' ');
+            $this->out->element('span', 'role', _('Creator'));
+        }
+    }
+
+    function showActions()
+    {
+        $this->startActions();
+        if (Event::handle('StartProfileListItemActionElements', array($this))) {
+            $this->showSubscribeButton();
+            Event::handle('EndProfileListItemActionElements', array($this));
+        }
+        $this->endActions();
+    }
+
+    function linkAttributes()
+    {
+        $aAttrs = parent::linkAttributes();
+
+        if (common_config('nofollow', 'members')) {
+            $aAttrs['rel'] .= ' nofollow';
+        }
+
+        return $aAttrs;
+    }
+
+    function homepageAttributes()
+    {
+        $aAttrs = parent::linkAttributes();
+
+        if (common_config('nofollow', 'members')) {
+            $aAttrs['rel'] = 'nofollow';
+        }
+
+        return $aAttrs;
+    }
+
+    /**
+     * Fetch necessary return-to arguments for the profile forms
+     * to return to this list when they're done.
+     * 
+     * @return array
+     */
+    protected function returnToArgs()
+    {
+        $args = array('action' => 'peopletagsubscribers',
+                      'tag' => $this->peopletag->tag,
+                      'tagger' => $this->profile->nickname);
+        $page = $this->out->arg('page');
+        if ($page) {
+            $args['param-page'] = $page;
+        }
+        return $args;
+    }
+}
diff --git a/actions/peopletagsubscriptions.php b/actions/peopletagsubscriptions.php
new file mode 100644 (file)
index 0000000..b45651d
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * People tags subscribed to by 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  Personal
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @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/peopletaglist.php';
+
+class PeopletagsubscriptionsAction extends OwnerDesignAction
+{
+    var $page = null;
+    var $profile = null;
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function title()
+    {
+        if ($this->page == 1) {
+            return sprintf(_("People tags subscriptions by %s"), $this->profile->nickname);
+        } else {
+            return sprintf(_("People tags subscriptions by %s, page %d"), $this->profile->nickname, $this->page);
+        }
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $nickname_arg = $this->arg('nickname');
+        $nickname = common_canonical_nickname($nickname_arg);
+
+        // Permanent redirect on non-canonical nickname
+
+        if ($nickname_arg != $nickname) {
+            $args = array('nickname' => $nickname);
+            if ($this->arg('page') && $this->arg('page') != 1) {
+                $args['page'] = $this->arg['page'];
+            }
+            common_redirect(common_local_url('peopletagsbyuser', $args), 301);
+            return false;
+        }
+
+        $user = User::staticGet('nickname', $nickname);
+
+        if (!$user) {
+            $this->clientError(_('No such user.'), 404);
+            return false;
+        }
+
+        $this->profile = $user->getProfile();
+
+        if (!$this->profile) {
+            $this->serverError(_('User has no profile.'));
+            return false;
+        }
+
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+        return true;
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PersonalGroupNav($this);
+        $nav->show();
+    }
+
+    function showAnonymousMessage()
+    {
+        $notice =
+          sprintf(_('These are people tags subscribed to by **%s**. ' .
+                    'People tags are how you sort similar ' .
+                    'people on %%%%site.name%%%%, a [micro-blogging]' .
+                    '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
+                    'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+                    'You can easily keep track of what they ' .
+                    'are doing by subscribing to the tag\'s timeline.' ), $this->profile->nickname);
+        $this->elementStart('div', array('id' => 'anon_notice'));
+        $this->raw(common_markup_to_html($notice));
+        $this->elementEnd('div');
+    }
+
+    function showContent()
+    {
+        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
+        $limit  = PEOPLETAGS_PER_PAGE + 1;
+
+        $ptags = $this->profile->getTagSubscriptions($offset, $limit);
+
+        $pl = new PeopletagList($ptags, $this);
+        $cnt = $pl->show();
+
+        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
+                          $this->page, 'peopletagsubscriptions', array('nickname' => $this->profile->id));
+    }
+
+    function showSections()
+    {
+        #TODO: tags with most subscribers
+        #TODO: tags with most "members"
+    }
+}
diff --git a/actions/profilecompletion.php b/actions/profilecompletion.php
new file mode 100644 (file)
index 0000000..8208f3b
--- /dev/null
@@ -0,0 +1,214 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2010, StatusNet, Inc.
+ *
+ * Subscription action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR . '/lib/peopletageditform.php';
+
+/**
+ * Subscription action
+ *
+ * Subscribing to a profile. Does not work for OMB 0.1 remote subscriptions,
+ * but may work for other remote subscription protocols, like OStatus.
+ *
+ * Takes parameters:
+ *
+ *    - subscribeto: a profile ID
+ *    - token: session token to prevent CSRF attacks
+ *    - ajax: boolean; whether to return Ajax or full-browser results
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+class ProfilecompletionAction extends Action
+{
+    var $user;
+    var $peopletag;
+    var $field;
+    var $msg;
+
+    /**
+     * Check pre-requisites and instantiate attributes
+     *
+     * @param Array $args array of arguments (URL, GET, POST)
+     *
+     * @return boolean success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        // CSRF protection
+
+        $token = $this->trimmed('token');
+
+        if (!$token || $token != common_session_token()) {
+            $this->clientError(_('There was a problem with your session token.'.
+                                 ' Try again, please.'));
+            return false;
+        }
+
+        // Only for logged-in users
+
+        $this->user = common_current_user();
+
+        if (empty($this->user)) {
+            $this->clientError(_('Not logged in.'));
+            return false;
+        }
+
+        $id = $this->arg('peopletag_id');
+        $this->peopletag = Profile_list::staticGet('id', $id);
+
+        if (empty($this->peopletag)) {
+            $this->clientError(_('No such peopletag.'));
+            return false;
+        }
+
+        $field = $this->arg('field');
+        if (!in_array($field, array('fulltext', 'nickname', 'fullname', 'description', 'location', 'uri'))) {
+            $this->clientError(sprintf(_('Unidentified field %s'), htmlspecialchars($field)), 404);
+            return false;
+        }
+        $this->field = $field;
+
+        return true;
+    }
+
+    /**
+     * Handle request
+     *
+     * Does the subscription and returns results.
+     *
+     * @param Array $args unused.
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        $this->msg = null;
+
+        $this->startHTML('text/xml;charset=utf-8');
+        $this->elementStart('head');
+        $this->element('title', null, _('Search results'));
+        $this->elementEnd('head');
+        $this->elementStart('body');
+        $profiles = $this->getResults();
+
+        if ($this->msg !== null) {
+            $this->element('p', 'error', $this->msg);
+        } else {
+            if (count($profiles) > 0) {
+                $this->elementStart('ul', array('id' => 'profile_search_results', 'class' => 'profile-lister'));
+                foreach ($profiles as $profile) {
+                    $this->showProfileItem($profile);
+                }
+                $this->elementEnd('ul');
+            } else {
+                $this->element('p', 'error', _('No results.'));
+            }
+        }
+        $this->elementEnd('body');
+        $this->elementEnd('html');
+    }
+
+    function getResults()
+    {
+        $profiles = array();
+        $q = $this->arg('q');
+        $q = strtolower($q);
+        if (strlen($q) < 3) {
+            $this->msg = _('The search string must be atleast 3 characters long');
+        }
+        $page = $this->arg('page');
+        $page = (int) (empty($page) ? 1 : $page);
+
+        $profile = new Profile();
+        $search_engine = $profile->getSearchEngine('profile');
+
+        if (Event::handle('StartProfileCompletionSearch', array($this, &$profile, $search_engine))) {
+            $search_engine->set_sort_mode('chron');
+            $search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);
+
+            if (false === $search_engine->query($q)) {
+                $cnt = 0;
+            }
+            else {
+                $cnt = $profile->find();
+            }
+            Event::handle('EndProfileCompletionSearch', $this, &$profile, $search_engine);
+        }
+
+        while ($profile->fetch()) {
+            $profiles[] = clone($profile);
+        }
+        return $this->filter($profiles);
+    }
+
+    function filter($profiles)
+    {
+        $current = $this->user->getProfile();
+        $filtered_profiles = array();
+        foreach ($profiles as $profile) {
+            if ($current->canTag($profile)) {
+                $filtered_profiles[] = $profile;
+            }
+        }
+        return $filtered_profiles;
+    }
+
+    function showProfileItem($profile)
+    {
+        $this->elementStart('li', 'entity_removable_profile');
+        $item = new TaggedProfileItem($this, $profile);
+        $item->show();
+        $this->elementStart('span', 'entity_actions');
+
+        if ($profile->isTagged($this->peopletag)) {
+            $untag = new UntagButton($this, $profile, $this->peopletag);
+            $untag->show();
+        } else {
+            $tag = new TagButton($this, $profile, $this->peopletag);
+            $tag->show();
+        }
+
+        $this->elementEnd('span');
+        $this->elementEnd('li');
+    }
+}
index e1d686ca292678cf2790683aea0fbd4266fc3f24..046bedf8ac13449b850b03da3c5d639f1969ca38 100644 (file)
@@ -279,18 +279,24 @@ class ProfilesettingsAction extends SettingsAction
                 return;
             }
 
-            if ($tagstring) {
-                $tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $tagstring));
-            } else {
-                $tags = array();
-            }
+            $tags = array();
+            $tag_priv = array();
+            if (is_string($tagstring) && strlen($tagstring) > 0) {
 
-            foreach ($tags as $tag) {
-                if (!common_valid_profile_tag($tag)) {
-                    // TRANS: Validation error in form for profile settings.
-                    // TRANS: %s is an invalid tag.
-                    $this->showForm(sprintf(_('Invalid tag: "%s".'), $tag));
-                    return;
+                $tags = preg_split('/[\s,]+/', $tagstring);
+
+                foreach ($tags as &$tag) {
+                    $private = @$tag[0] === '.';
+
+                    $tag = common_canonical_tag($tag);
+                    if (!common_valid_profile_tag($tag)) {
+                        // TRANS: Validation error in form for profile settings.
+                        // TRANS: %s is an invalid tag.
+                        $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
+                        return;
+                    }
+
+                    $tag_priv[$tag] = $private;
                 }
             }
 
@@ -421,7 +427,7 @@ class ProfilesettingsAction extends SettingsAction
             }
 
             // Set the user tags
-            $result = $user->setSelfTags($tags);
+            $result = $user->setSelfTags($tags, $tag_priv);
 
             if (!$result) {
                 // TRANS: Server error thrown when user profile settings tags could not be saved.
diff --git a/actions/profiletagbyid.php b/actions/profiletagbyid.php
new file mode 100644 (file)
index 0000000..7de5737
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Permalink for 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);
+}
+
+class ProfiletagbyidAction extends Action
+{
+    /** peopletag we're viewing. */
+    var $peopletag = null;
+
+    /**
+     * Is this page read-only?
+     *
+     * @return boolean true
+     */
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $id = $this->arg('id');
+        $tagger_id = $this->arg('tagger_id');
+
+        if (!$id) {
+            $this->clientError(_('No ID.'));
+            return false;
+        }
+
+        common_debug("Peopletag id $id by user id $tagger_id");
+
+        $this->peopletag = Profile_list::staticGet('id', $id);
+
+        if (!$this->peopletag) {
+            $this->clientError(_('No such people tag.'), 404);
+            return false;
+        }
+
+        $user = User::staticGet('id', $tagger_id);
+        if (!$user) {
+            // remote peopletag, permanently redirect
+            common_redirect($this->peopletag->permalink(), 301);
+        }
+
+        return true;
+    }
+
+    /**
+     * Handle the request
+     *
+     * Shows a profile for the group, some controls, and a list of
+     * group notices.
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        common_redirect($this->peopletag->homeUrl(), 303);
+    }
+}
index 727c76d528a3531543b752fe07704c18dac04b4f..ca9af4601ef4d72fe76e8fa25e67308a35efd811 100644 (file)
@@ -232,6 +232,8 @@ class PublicAction extends Action
         $pop->show();
         $gbp = new GroupsByMembersSection($this);
         $gbp->show();
+        $ptp = new PeopletagsBySubsSection($this);
+        $ptp->show();
         $feat = new FeaturedUsersSection($this);
         $feat->show();
     }
diff --git a/actions/publicpeopletagcloud.php b/actions/publicpeopletagcloud.php
new file mode 100644 (file)
index 0000000..dc252fe
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Public tag cloud for notices
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Public
+ * @package   StatusNet
+ * @author    Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 Mike Cochrane
+ * @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); }
+
+define('TAGS_PER_PAGE', 100);
+
+/**
+ * Public tag cloud for notices
+ *
+ * @category Personal
+ * @package  StatusNet
+ * @author    Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 Mike Cochrane
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @link     http://status.net/
+ */
+
+class PublicpeopletagcloudAction extends Action
+{
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function title()
+    {
+        return _('Public people tag cloud');
+    }
+
+    function showPageNotice()
+    {
+        $this->element('p', 'instructions',
+                       sprintf(_('These are most used people tags on %s '),
+                               common_config('site', 'name')));
+    }
+
+    function showEmptyList()
+    {
+        $message = _('No one has [tagged](%%doc.tags%%) anyone yet.') . ' ';
+
+        if (common_logged_in()) {
+            $message .= _('Be the first to tag someone!');
+        }
+        else {
+            $message .= _('Why not [register an account](%%action.register%%) and be the first to tag someone!');
+        }
+
+        $this->elementStart('div', 'guide');
+        $this->raw(common_markup_to_html($message));
+        $this->elementEnd('div');
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PublicGroupNav($this);
+        $nav->show();
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    function showContent()
+    {
+        // XXX: cache this
+
+        $tags = new Profile_tag();
+        $plist = new Profile_list();
+        $plist->private = false;
+
+        $tags->joinAdd($plist);
+        $tags->selectAdd();
+        $tags->selectAdd('profile_tag.tag');
+        $tags->selectAdd('count(profile_tag.tag) as weight');
+        $tags->groupBy('profile_tag.tag');
+        $tags->orderBy('weight DESC');
+
+        $tags->limit(TAGS_PER_PAGE);
+
+        $cnt = $tags->find();
+
+        if ($cnt > 0) {
+            $this->elementStart('div', array('id' => 'tagcloud',
+                                             'class' => 'section'));
+
+            $tw = array();
+            $sum = 0;
+            while ($tags->fetch()) {
+                $tw[$tags->tag] = $tags->weight;
+                $sum += $tags->weight;
+            }
+
+            ksort($tw);
+
+            $this->elementStart('dl');
+            $this->element('dt', null, _('People tag cloud'));
+            $this->elementStart('dd');
+            $this->elementStart('ul', 'tags xoxo tag-cloud');
+            foreach ($tw as $tag => $weight) {
+                if ($sum) {
+                    $weightedSum = $weight/$sum;
+                } else {
+                    $weightedSum = 0.5;
+                }
+                $this->showTag($tag, $weight, $weightedSum);
+            }
+            $this->elementEnd('ul');
+            $this->elementEnd('dd');
+            $this->elementEnd('dl');
+            $this->elementEnd('div');
+        } else {
+            $this->showEmptyList();
+        }
+    }
+
+    function showTag($tag, $weight, $relative)
+    {
+        if ($relative > 0.1) {
+            $rel =  'tag-cloud-7';
+        } else if ($relative > 0.05) {
+            $rel = 'tag-cloud-6';
+        } else if ($relative > 0.02) {
+            $rel = 'tag-cloud-5';
+        } else if ($relative > 0.01) {
+            $rel = 'tag-cloud-4';
+        } else if ($relative > 0.005) {
+            $rel = 'tag-cloud-3';
+        } else if ($relative > 0.002) {
+            $rel = 'tag-cloud-2';
+        } else {
+            $rel = 'tag-cloud-1';
+        }
+
+        $this->elementStart('li', $rel);
+
+        $count = ($weight == 1) ? '1 person tagged' : '%d people tagged';
+        $this->element('a', array('href'  => common_local_url('peopletag', array('tag' => $tag)),
+                                  'title' => sprintf(_($count), $weight)), $tag);
+        $this->elementEnd('li');
+    }
+}
diff --git a/actions/removepeopletag.php b/actions/removepeopletag.php
new file mode 100644 (file)
index 0000000..aa8ae2b
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2010, StatusNet, Inc.
+ *
+ * Subscription action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR . '/lib/togglepeopletag.php';
+
+/**
+ * Subscription action
+ *
+ * Subscribing to a profile. Does not work for OMB 0.1 remote subscriptions,
+ * but may work for other remote subscription protocols, like OStatus.
+ *
+ * Takes parameters:
+ *
+ *    - subscribeto: a profile ID
+ *    - token: session token to prevent CSRF attacks
+ *    - ajax: boolean; whether to return Ajax or full-browser results
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category  Action
+ * @package   StatusNet
+ * @author    Shashi Gowda <connect2shashi@gmail.com>
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link      http://status.net/
+ */
+
+class RemovepeopletagAction extends Action
+{
+    var $user;
+    var $tagged;
+    var $peopletag;
+
+    /**
+     * Check pre-requisites and instantiate attributes
+     *
+     * @param Array $args array of arguments (URL, GET, POST)
+     *
+     * @return boolean success flag
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        // CSRF protection
+
+        $token = $this->trimmed('token');
+
+        if (!$token || $token != common_session_token()) {
+            $this->clientError(_('There was a problem with your session token.'.
+                                 ' Try again, please.'));
+            return false;
+        }
+
+        // Only for logged-in users
+
+        $this->user = common_current_user();
+
+        if (empty($this->user)) {
+            $this->clientError(_('Not logged in.'));
+            return false;
+        }
+
+        // Profile to subscribe to
+
+        $tagged_id = $this->arg('tagged');
+
+        $this->tagged = Profile::staticGet('id', $tagged_id);
+
+        if (empty($this->tagged)) {
+            $this->clientError(_('No such profile.'));
+            return false;
+        }
+
+        $id = $this->arg('peopletag_id');
+        $this->peopletag = Profile_list::staticGet('id', $id);
+
+        if (empty($this->peopletag)) {
+            $this->clientError(_('No such peopletag.'));
+            return false;
+        }
+
+        // OMB 0.1 doesn't have a mechanism for local-server-
+        // originated tag.
+
+        $omb01 = Remote_profile::staticGet('id', $tagged_id);
+
+        if (!empty($omb01)) {
+            $this->clientError(_('You cannot tag or untag an OMB 0.1'.
+                                 ' remote profile with this action.'));
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Handle request
+     *
+     * Does the subscription and returns results.
+     *
+     * @param Array $args unused.
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        // Throws exception on error
+
+        $ptag = Profile_tag::unTag($this->user->id, $this->tagged->id,
+                                $this->peopletag->tag);
+
+        if (!$ptag) {
+            $user = User::staticGet('id', $this->tagged->id);
+            if ($user) {
+                $this->clientError(
+                        sprintf(_('There was an unexpected error while tagging %s'),
+                        $user->nickname));
+            } else {
+                $this->clientError(sprintf(_('There was a problem tagging %s.' .
+                                      'The remote server is probably not responding correctly, ' .
+                                      'please try retrying later.'), $this->profile->profileurl));
+            }
+            return false;
+        }
+        if ($this->boolean('ajax')) {
+            $this->startHTML('text/xml;charset=utf-8');
+            $this->elementStart('head');
+            $this->element('title', null, _('Untagged'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $unsubscribe = new TagButton($this, $this->tagged, $this->peopletag);
+            $unsubscribe->show();
+            $this->elementEnd('body');
+            $this->elementEnd('html');
+        } else {
+            $url = common_local_url('subscriptions',
+                                    array('nickname' => $this->user->nickname));
+            common_redirect($url, 303);
+        }
+    }
+}
diff --git a/actions/selftag.php b/actions/selftag.php
new file mode 100644 (file)
index 0000000..0efb896
--- /dev/null
@@ -0,0 +1,204 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Action for showing profiles self-tagged with a given tag
+ *
+ * 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>
+ * @author    Zach Copley <zach@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') && !defined('LACONICA')) {
+    exit(1);
+}
+
+/**
+ * This class outputs a paginated list of profiles self-tagged with a given tag
+ *
+ * @category Output
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      Action
+ */
+
+class SelftagAction extends Action
+{
+
+    var $tag  = null;
+    var $page = null;
+
+    /**
+     * For initializing members of the class.
+     *
+     * @param array $argarray misc. arguments
+     *
+     * @return boolean true
+     */
+    function prepare($argarray)
+    {
+        parent::prepare($argarray);
+
+        $this->tag = $this->trimmed('tag');
+
+        if (!common_valid_profile_tag($this->tag)) {
+            $this->clientError(sprintf(_('Not a valid people tag: %s.'),
+                $this->tag));
+            return;
+        }
+
+        $this->page = ($this->arg('page')) ? $this->arg('page') : 1;
+
+        common_set_returnto($this->selfUrl());
+
+        return true;
+    }
+
+    /**
+     * Handler method
+     *
+     * @param array $argarray is ignored since it's now passed in in prepare()
+     *
+     * @return boolean is read only action?
+     */
+    function handle($argarray)
+    {
+        parent::handle($argarray);
+        $this->showPage();
+    }
+
+    /**
+     * Whips up a query to get a list of profiles based on the provided
+     * people tag and page, initalizes a ProfileList widget, and displays
+     * it to the user.
+     *
+     * @return nothing
+     */
+    function showContent()
+    {
+
+        $profile = new Profile();
+
+        $offset = ($this->page - 1) * PROFILES_PER_PAGE;
+        $limit  = PROFILES_PER_PAGE + 1;
+
+        if (common_config('db', 'type') == 'pgsql') {
+            $lim = ' LIMIT ' . $limit . ' OFFSET ' . $offset;
+        } else {
+            $lim = ' LIMIT ' . $offset . ', ' . $limit;
+        }
+
+        // XXX: memcached this
+
+        $qry =  'SELECT profile.* ' .
+                'FROM profile JOIN ( profile_tag, profile_list ) ' .
+                'ON profile.id = profile_tag.tagger ' .
+                'AND profile_tag.tagger = profile_list.tagger ' .
+                'AND profile_list.tag = profile_tag.tag ' .
+                'WHERE profile_tag.tagger = profile_tag.tagged ' .
+                "AND profile_tag.tag = '%s' ";
+
+        $user = common_current_user();
+        if (empty($user)) {
+            $qry .= 'AND profile_list.private = false ';
+        } else {
+            $qry .= 'AND (profile_list.tagger = ' . $user->id .
+                    ' OR profile_list.private = false) ';
+        }
+
+        $qry .= 'ORDER BY profile_tag.modified DESC%s';
+
+        $profile->query(sprintf($qry, $this->tag, $lim));
+
+        $ptl = new SelfTagProfileList($profile, $this); // pass the ammunition
+        $cnt = $ptl->show();
+
+        $this->pagination($this->page > 1,
+                          $cnt > PROFILES_PER_PAGE,
+                          $this->page,
+                          'selftag',
+                          array('tag' => $this->tag));
+    }
+
+    /**
+     * Returns the page title
+     *
+     * @return string page title
+     */
+    function title()
+    {
+        return sprintf(_('Users self-tagged with %1$s - page %2$d'),
+            $this->tag, $this->page);
+    }
+
+}
+
+class SelfTagProfileList extends ProfileList
+{
+    function newListItem($profile)
+    {
+        return new SelfTagProfileListItem($profile, $this->action);
+    }
+}
+
+class SelfTagProfileListItem extends ProfileListItem
+{
+    function linkAttributes()
+    {
+        $aAttrs = parent::linkAttributes();
+
+        if (common_config('nofollow', 'selftag')) {
+            $aAttrs['rel'] .= ' nofollow';
+        }
+
+        return $aAttrs;
+    }
+
+    function homepageAttributes()
+    {
+        $aAttrs = parent::linkAttributes();
+
+        if (common_config('nofollow', 'selftag')) {
+            $aAttrs['rel'] = 'nofollow';
+        }
+
+        return $aAttrs;
+    }
+
+    function showTags()
+    {
+        $selftags = new SelfTagsWidget($this->out, $this->profile, $this->profile);
+        $selftags->show();
+
+        $user = common_current_user();
+
+        if (!empty($user) && $user->id != $this->profile->id &&
+                $user->getProfile()->canTag($this->profile)) {
+            $yourtags = new PeopleTagsWidget($this->out, $user, $this->profile);
+            $yourtags->show();
+        }
+    }
+}
diff --git a/actions/showprofiletag.php b/actions/showprofiletag.php
new file mode 100644 (file)
index 0000000..a4cace6
--- /dev/null
@@ -0,0 +1,354 @@
+<?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/>.
+ *
+ * @category Actions
+ * @package  Actions
+ * @license  GNU Affero General Public License http://www.gnu.org/licenses/
+ * @link     http://status.net
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+require_once INSTALLDIR.'/lib/profileminilist.php';
+require_once INSTALLDIR.'/lib/peopletaglist.php';
+require_once INSTALLDIR.'/lib/noticelist.php';
+require_once INSTALLDIR.'/lib/feedlist.php';
+
+class ShowprofiletagAction extends Action
+{
+    var $notice, $tagger, $peopletag;
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $tagger_arg = $this->arg('tagger');
+        $tag_arg = $this->arg('tag');
+        $tagger = common_canonical_nickname($tagger_arg);
+        $tag = common_canonical_tag($tag_arg);
+
+        // Permanent redirect on non-canonical nickname
+
+        if ($tagger_arg != $tagger || $tag_arg != $tag) {
+            $args = array('tagger' => $nickname, 'tag' => $tag);
+            if ($this->page != 1) {
+                $args['page'] = $this->page;
+            }
+            common_redirect(common_local_url('showprofiletag', $args), 301);
+            return false;
+        }
+
+        if (!$tagger) {
+            $this->clientError(_('No tagger.'), 404);
+            return false;
+        }
+
+        $user = User::staticGet('nickname', $tagger);
+
+        if (!$user) {
+            $this->clientError(_('No such user.'), 404);
+            return false;
+        }
+
+        $this->tagger = $user->getProfile();
+        $this->peopletag = Profile_list::pkeyGet(array('tagger' => $user->id, 'tag' => $tag));
+
+        $current = common_current_user();
+        $can_see = !empty($this->peopletag) && (!$this->peopletag->private ||
+                   ($this->peopletag->private && $this->peopletag->tagger === $current->id));
+
+        if (!$can_see) {
+            $this->clientError(_('No such peopletag.'), 404);
+            return false;
+        }
+
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+        $this->notice = $this->peopletag->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+
+        if ($this->page > 1 && $this->notice->N == 0) {
+            // TRANS: Server error when page not found (404)
+            $this->serverError(_('No such page.'), $code = 404);
+        }
+
+        return true;
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+
+        if (!$this->peopletag) {
+            $this->clientError(_('No such user.'));
+            return;
+        }
+
+        $this->showPage();
+    }
+
+    function title()
+    {
+        if ($this->page > 1) {
+
+            if($this->peopletag->private) {
+                return sprintf(_('Private timeline for people tagged %s by you, page %d'),
+                                $this->peopletag->tag, $this->page);
+            }
+
+            $current = common_current_user();
+            if (!empty($current) && $current->id == $this->peopletag->tagger) {
+                return sprintf(_('Timeline for people tagged %s by you, page %d'),
+                                $this->peopletag->tag, $this->page);
+            }
+
+            // TRANS: Page title. %1$s is user nickname, %2$d is page number
+            return sprintf(_('Timeline for people tagged %1$s by %2$s, page %3$d'),
+                                $this->peopletag->tag,
+                                $this->tagger->nickname,
+                                $this->page
+                          );
+        } else {
+
+            if($this->peopletag->private) {
+                return sprintf(_('Private timeline of people tagged %s by you'),
+                                $this->peopletag->tag, $this->page);
+            }
+
+            $current = common_current_user();
+            if (!empty($current) && $current->id == $this->peopletag->tagger) {
+                return sprintf(_('Timeline for people tagged %s by you'),
+                                $this->peopletag->tag, $this->page);
+            }
+
+            // TRANS: Page title. %1$s is user nickname, %2$d is page number
+            return sprintf(_('Timeline for people tagged %1$s by %2$s'),
+                                $this->peopletag->tag,
+                                $this->tagger->nickname, 
+                                $this->page
+                          );
+        }
+    }
+
+    function getFeeds()
+    {
+        #XXX: make these actually work
+        return array(new Feed(Feed::RSS2,
+                common_local_url(
+                    'ApiTimelineList', array(
+                        'user' => $this->tagger->id,
+                        'id' => $this->peopletag->id,
+                        'format' => 'rss'
+                    )
+                ),
+            // TRANS: %1$s is user nickname
+                sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->tagger->nickname)),
+            new Feed(Feed::ATOM,
+                common_local_url(
+                    'ApiTimelineList', array(
+                        'user' => $this->tagger->id,
+                        'id' => $this->peopletag->id,
+                        'format' => 'atom'
+                    )
+                ),
+                // TRANS: %1$s is user nickname
+                sprintf(_('Feed for people tagged %s by %s (Atom)'),
+                            $this->peopletag->tag, $this->tagger->nickname
+                       )
+              )
+        );
+    }
+
+    function showLocalNav()
+    {
+        $nav = new PeopletagGroupNav($this);
+        $nav->show();
+    }
+
+    function showEmptyListMessage()
+    {
+        // TRANS: %1$s is user nickname
+        $message = sprintf(_('This is the timeline for people tagged %s by %s but no one has posted anything yet.'), $this->peopletag->tag, $this->tagger->nickname) . ' ';
+
+        if (common_logged_in()) {
+            $current_user = common_current_user();
+            if ($this->tagger->id == $current_user->id) {
+                $message .= _('Try tagging more people.');
+            }
+        } else {
+            $message .= _('Why not [register an account](%%%%action.register%%%%) and start following this timeline.');
+        }
+
+        $this->elementStart('div', 'guide');
+        $this->raw(common_markup_to_html($message));
+        $this->elementEnd('div');
+    }
+
+    function showContent()
+    {
+        $this->showPeopletag();
+        $this->showNotices();
+    }
+
+    function showPeopletag()
+    {
+        $cur = common_current_user();
+        $tag = new Peopletag($this->peopletag, $cur, $this);
+        $tag->show();
+    }
+
+    function showNotices()
+    {
+        if (Event::handle('StartShowProfileTagContent', array($this))) {
+            $nl = new NoticeList($this->notice, $this);
+
+            $cnt = $nl->show();
+
+            if (0 == $cnt) {
+                $this->showEmptyListMessage();
+            }
+
+            $this->pagination(
+                $this->page > 1, $cnt > NOTICES_PER_PAGE,
+                $this->page, 'showprofiletag', array('tag' => $this->peopletag->tag,
+                                                     'tagger' => $this->tagger->nickname)
+            );
+
+            Event::handle('EndShowProfileTagContent', array($this));
+        }
+    }
+
+    function showSections()
+    {
+        $this->showTagged();
+        if (!$this->peopletag->private) {
+            $this->showSubscribers();
+        }
+        # $this->showStatistics();
+    }
+
+    function showPageTitle()
+    {
+        $this->element('h1', null, $this->title());
+    }
+
+    function showTagged()
+    {
+        $profile = $this->peopletag->getTagged(0, PROFILES_PER_MINILIST + 1);
+
+        $this->elementStart('div', array('id' => 'entity_tagged',
+                                         'class' => 'section'));
+        if (Event::handle('StartShowTaggedProfilesMiniList', array($this))) {
+
+            $title = '';
+
+            $current = common_current_user();
+            if(!empty($current) && $this->peopletag->tagger == $current->id) {
+                $title =  sprintf(_('People tagged %s by you'), $this->peopletag->tag);
+            } else {
+                $title = sprintf(_('People tagged %1$s by %2$s'),
+                                $this->peopletag->tag,
+                                $this->tagger->nickname);
+            }
+
+            $this->element('h2', null, $title);
+
+            $cnt = 0;
+
+            if (!empty($profile)) {
+                $pml = new ProfileMiniList($profile, $this);
+                $cnt = $pml->show();
+                if ($cnt == 0) {
+                    $this->element('p', null, _('(None)'));
+                }
+            }
+
+            if ($cnt > PROFILES_PER_MINILIST) {
+                $this->elementStart('p');
+                $this->element('a', array('href' => common_local_url('taggedprofiles',
+                                                                     array('nickname' => $this->tagger->nickname,
+                                                                           'profiletag' => $this->peopletag->tag)),
+                                          'class' => 'more'),
+                               _('Show all'));
+                $this->elementEnd('p');
+            }
+
+            Event::handle('EndShowTaggedProfilesMiniList', array($this));
+        }
+        $this->elementEnd('div');
+    }
+
+    function showSubscribers()
+    {
+        $profile = $this->peopletag->getSubscribers(0, PROFILES_PER_MINILIST + 1);
+
+        $this->elementStart('div', array('id' => 'entity_subscribers',
+                                         'class' => 'section'));
+        if (Event::handle('StartShowProfileTagSubscribersMiniList', array($this))) {
+            $this->element('h2', null, _('Subscribers'));
+
+            $cnt = 0;
+
+            if (!empty($profile)) {
+                $pml = new ProfileMiniList($profile, $this);
+                $cnt = $pml->show();
+                if ($cnt == 0) {
+                    $this->element('p', null, _('(None)'));
+                }
+            }
+
+            if ($cnt > PROFILES_PER_MINILIST) {
+                $this->elementStart('p');
+                $this->element('a', array('href' => common_local_url('profiletagsubscribers',
+                                                                     array('nickname' => $this->tagger->nickname,
+                                                                           'profiletag' => $this->peopletag->tag)),
+                                          'class' => 'more'),
+                               _('All subscribers'));
+                $this->elementEnd('p');
+            }
+
+            Event::handle('EndShowProfileTagSubscribersMiniList', array($this));
+        }
+        $this->elementEnd('div');
+    }
+}
+
+class Peopletag extends PeopletagListItem
+{
+    function showStart()
+    {
+        $mode = $this->peopletag->private ? 'private' : 'public';
+        $this->out->elementStart('div', array('class' => 'hentry peopletag peopletag-profile mode-'.$mode,
+                                             'id' => 'peopletag-' . $this->peopletag->id));
+    }
+
+    function showEnd()
+    {
+        $this->out->elementEnd('div');
+    }
+
+    function showAvatar()
+    {
+        parent::showAvatar(AVATAR_PROFILE_SIZE);
+    }
+}
diff --git a/actions/subscribepeopletag.php b/actions/subscribepeopletag.php
new file mode 100644 (file)
index 0000000..e38ecb2
--- /dev/null
@@ -0,0 +1,144 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Subscribe 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);
+}
+
+/**
+ * Subscribe 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 SubscribepeopletagAction extends Action
+{
+    var $peopletag = null;
+    var $tagger = null;
+
+    /**
+     * Prepare to run
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        if (!common_logged_in()) {
+            $this->clientError(_('You must be logged in to unsubscribe to a peopletag.'));
+            return false;
+        }
+        // Only allow POST requests
+
+        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+            $this->clientError(_('This action only accepts POST requests.'));
+            return false;
+        }
+
+        // CSRF protection
+
+        $token = $this->trimmed('token');
+
+        if (!$token || $token != common_session_token()) {
+            $this->clientError(_('There was a problem with your session token.'.
+                                 ' Try again, please.'));
+            return false;
+        }
+
+        $tagger_arg = $this->trimmed('tagger');
+        $tag_arg = $this->trimmed('tag');
+
+        $id = intval($this->arg('id'));
+        if ($id) {
+            $this->peopletag = Profile_list::staticGet('id', $id);
+        } else {
+            $this->clientError(_('No ID given.'), 404);
+            return false;
+        }
+
+        if (!$this->peopletag || $this->peopletag->private) {
+            $this->clientError(_('No such peopletag.'), 404);
+            return false;
+        }
+
+        $this->tagger = Profile::staticGet('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();
+
+        try {
+            Profile_tag_subscription::add($this->peopletag, $cur);
+        } catch (Exception $e) {
+            $this->serverError(sprintf(_('Could not subscribe user %1$s to peopletag %2$s.'),
+                                       $cur->nickname, $this->peopletag->tag) . ' ' . $e->getMessage());
+        }
+
+        if ($this->boolean('ajax')) {
+            $this->startHTML('text/xml;charset=utf-8');
+            $this->elementStart('head');
+            $this->element('title', null, sprintf(_('%1$s subscribed to peopletag %2$s by %3$s'),
+                                                  $cur->nickname,
+                                                  $this->peopletag->tag,
+                                                  $this->tagger->nickname));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $lf = new UnsubscribePeopletagForm($this, $this->peopletag);
+            $lf->show();
+            $this->elementEnd('body');
+            $this->elementEnd('html');
+        } else {
+            common_redirect(common_local_url('peopletagsubscribers',
+                                array('tagger' => $this->tagger->nickname,
+                                      'tag' =>$this->peopletag->tag)),
+                            303);
+        }
+    }
+}
diff --git a/actions/tagother.php b/actions/tagother.php
deleted file mode 100644 (file)
index 258c13b..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-<?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); }
-
-require_once(INSTALLDIR.'/lib/settingsaction.php');
-
-class TagotherAction extends Action
-{
-    var $profile = null;
-    var $error = null;
-
-    function prepare($args)
-    {
-        parent::prepare($args);
-        if (!common_logged_in()) {
-            $this->clientError(_('Not logged in.'), 403);
-            return false;
-        }
-
-        $id = $this->trimmed('id');
-        if (!$id) {
-            $this->clientError(_('No ID argument.'));
-            return false;
-        }
-
-        $this->profile = Profile::staticGet('id', $id);
-
-        if (!$this->profile) {
-            $this->clientError(_('No profile with that ID.'));
-            return false;
-        }
-
-        return true;
-    }
-
-    function handle($args)
-    {
-        parent::handle($args);
-        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
-            $this->saveTags();
-        } else {
-            $this->showForm($profile);
-        }
-    }
-
-    function title()
-    {
-        return sprintf(_('Tag %s'), $this->profile->nickname);
-    }
-
-    function showForm($error=null)
-    {
-        $this->error = $error;
-        $this->showPage();
-    }
-
-    function showContent()
-    {
-        $this->elementStart('div', 'entity_profile vcard author');
-        $this->element('h2', null, _('User profile'));
-
-        $avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
-        $this->element('img', array('src' => ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE),
-                                    'class' => 'photo avatar entity_depiction',
-                                    'width' => AVATAR_PROFILE_SIZE,
-                                    'height' => AVATAR_PROFILE_SIZE,
-                                    'alt' =>
-                                    ($this->profile->fullname) ? $this->profile->fullname :
-                                    $this->profile->nickname));
-
-        $this->element('a', array('href' => $this->profile->profileurl,
-                                  'class' => 'entity_nickname nickname'),
-                       $this->profile->nickname);
-
-        if ($this->profile->fullname) {
-            $this->element('div', 'fn entity_fn', $this->profile->fullname);
-        }
-
-        if ($this->profile->location) {
-            $this->element('div', 'label entity_location', $this->profile->location);
-        }
-
-        if ($this->profile->homepage) {
-            $this->element('a', array('href' => $this->profile->homepage,
-                                      'rel' => 'me',
-                                      'class' => 'url entity_url'),
-                           $this->profile->homepage);
-        }
-
-        if ($this->profile->bio) {
-            $this->element('div', 'note entity_note', $this->profile->bio);
-        }
-
-        $this->elementEnd('div');
-
-        $this->elementStart('form', array('method' => 'post',
-                                           'id' => 'form_tag_user',
-                                           'class' => 'form_settings',
-                                           'name' => 'tagother',
-                                           'action' => common_local_url('tagother', array('id' => $this->profile->id))));
-
-        $this->elementStart('fieldset');
-        $this->element('legend', null, _('Tag user'));
-        $this->hidden('token', common_session_token());
-        $this->hidden('id', $this->profile->id);
-
-        $user = common_current_user();
-
-        $this->elementStart('ul', 'form_data');
-        $this->elementStart('li');
-        $this->input('tags', _('Tags'),
-                     ($this->arg('tags')) ? $this->arg('tags') : implode(' ', Profile_tag::getTags($user->id, $this->profile->id)),
-                     _('Tags for this user (letters, numbers, -, ., and _), comma- or space- separated'));
-        $this->elementEnd('li');
-        $this->elementEnd('ul');
-        $this->submit('save', _('Save'));
-        $this->elementEnd('fieldset');
-        $this->elementEnd('form');
-    }
-
-    function saveTags()
-    {
-        $id = $this->trimmed('id');
-        $tagstring = $this->trimmed('tags');
-        $token = $this->trimmed('token');
-
-        if (!$token || $token != common_session_token()) {
-            $this->showForm(_('There was a problem with your session token. '.
-                              'Try again, please.'));
-            return;
-        }
-
-        if (is_string($tagstring) && strlen($tagstring) > 0) {
-
-            $tags = array_map('common_canonical_tag',
-                              preg_split('/[\s,]+/', $tagstring));
-
-            foreach ($tags as $tag) {
-                if (!common_valid_profile_tag($tag)) {
-                    $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
-                    return;
-                }
-            }
-        } else {
-            $tags = array();
-        }
-
-        $user = common_current_user();
-
-        if (!Subscription::pkeyGet(array('subscriber' => $user->id,
-                                         'subscribed' => $this->profile->id)) &&
-            !Subscription::pkeyGet(array('subscriber' => $this->profile->id,
-                                         'subscribed' => $user->id)))
-        {
-            $this->clientError(_('You can only tag people you are subscribed to or who are subscribed to you.'));
-            return;
-        }
-
-        $result = Profile_tag::setTags($user->id, $this->profile->id, $tags);
-
-        if (!$result) {
-            $this->clientError(_('Could not save tags.'));
-            return;
-        }
-
-        $action = $user->isSubscribed($this->profile) ? 'subscriptions' : 'subscribers';
-
-        if ($this->boolean('ajax')) {
-            $this->startHTML('text/xml;charset=utf-8');
-            $this->elementStart('head');
-            $this->element('title', null, _('Tags'));
-            $this->elementEnd('head');
-            $this->elementStart('body');
-            $this->elementStart('p', 'subtags');
-            foreach ($tags as $tag) {
-                $this->element('a', array('href' => common_local_url($action,
-                                                                     array('nickname' => $user->nickname,
-                                                                           'tag' => $tag))),
-                               $tag);
-            }
-            $this->elementEnd('p');
-            $this->elementEnd('body');
-            $this->elementEnd('html');
-        } else {
-            common_redirect(common_local_url($action, array('nickname' =>
-                                                            $user->nickname)),
-                            303);
-        }
-    }
-
-    function showPageNotice()
-    {
-        if ($this->error) {
-            $this->element('p', 'error', $this->error);
-        } else {
-            $this->elementStart('div', 'instructions');
-            $this->element('p', null,
-                           _('Use this form to add tags to your subscribers or subscriptions.'));
-            $this->elementEnd('div');
-        }
-    }
-}
-
diff --git a/actions/tagprofile.php b/actions/tagprofile.php
new file mode 100644 (file)
index 0000000..8c0e039
--- /dev/null
@@ -0,0 +1,249 @@
+<?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); }
+
+require_once INSTALLDIR . '/lib/settingsaction.php';
+require_once INSTALLDIR . '/lib/peopletags.php';
+
+class TagprofileAction extends Action
+{
+    var $profile = null;
+    var $error = null;
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+        if (!common_logged_in()) {
+            common_set_returnto($_SERVER['REQUEST_URI']);
+            if (Event::handle('RedirectToLogin', array($this, null))) {
+                common_redirect(common_local_url('login'), 303);
+            }
+        }
+
+        $id = $this->trimmed('id');
+        if (!$id) {
+            $this->profile = false;
+        } else {
+            $this->profile = Profile::staticGet('id', $id);
+
+            if (!$this->profile) {
+                $this->clientError(_('No profile with that ID.'));
+                return false;
+            }
+        }
+
+        $current = common_current_user()->getProfile();
+        if ($this->profile && !$current->canTag($this->profile)) {
+            $this->clientError(_('You cannot tag this user.'));
+        }
+        return true;
+    }
+
+    function handle($args)
+    {
+        parent::handle($args);
+        if (Event::handle('StartTagProfileAction', array($this, $this->profile))) {
+            if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+                $this->saveTags();
+            } else {
+                $this->showForm();
+            }
+            Event::handle('EndTagProfileAction', array($this, $this->profile));
+        }
+    }
+
+    function title()
+    {
+        if (!$this->profile) {
+            return _('Tag a profile');
+        }
+        return sprintf(_('Tag %s'), $this->profile->nickname);
+    }
+
+    function showForm($error=null)
+    {
+        $this->error = $error;
+        if ($this->boolean('ajax')) {
+            $this->startHTML('text/xml;charset=utf-8');
+            $this->elementStart('head');
+            $this->element('title', null, _('Error'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $this->element('p', 'error', $error);
+            $this->elementEnd('body');
+            $this->elementEnd('html');
+        } else {
+            $this->showPage();
+        }
+    }
+
+    function showContent()
+    {
+        if (Event::handle('StartShowTagProfileForm', array($this, $this->profile)) && $this->profile) {
+            $this->elementStart('div', 'entity_profile vcard author');
+            $this->element('h2', null, _('User profile'));
+
+            $avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
+            $this->element('img', array('src' => ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE),
+                                        'class' => 'photo avatar entity_depiction',
+                                        'width' => AVATAR_PROFILE_SIZE,
+                                        'height' => AVATAR_PROFILE_SIZE,
+                                        'alt' =>
+                                        ($this->profile->fullname) ? $this->profile->fullname :
+                                        $this->profile->nickname));
+
+            $this->element('a', array('href' => $this->profile->profileurl,
+                                      'class' => 'entity_nickname nickname'),
+                           $this->profile->nickname);
+            if ($this->profile->fullname) {
+                $this->element('div', 'fn entity_fn', $this->profile->fullname);
+            }
+
+            if ($this->profile->location) {
+                $this->element('div', 'label entity_location', $this->profile->location);
+            }
+
+            if ($this->profile->homepage) {
+                $this->element('a', array('href' => $this->profile->homepage,
+                                          'rel' => 'me',
+                                          'class' => 'url entity_url'),
+                               $this->profile->homepage);
+            }
+
+            if ($this->profile->bio) {
+                $this->element('div', 'note entity_note', $this->profile->bio);
+            }
+
+            $this->elementEnd('div');
+
+            $this->elementStart('form', array('method' => 'post',
+                                               'id' => 'form_tag_user',
+                                               'class' => 'form_settings',
+                                               'name' => 'tagprofile',
+                                               'action' => common_local_url('tagprofile', array('id' => $this->profile->id))));
+
+            $this->elementStart('fieldset');
+            $this->element('legend', null, _('Tag user'));
+            $this->hidden('token', common_session_token());
+            $this->hidden('id', $this->profile->id);
+
+            $user = common_current_user();
+
+            $this->elementStart('ul', 'form_data');
+            $this->elementStart('li');
+
+            $tags = Profile_tag::getTagsArray($user->id, $this->profile->id, $user->id);
+            $this->input('tags', _('Tags'),
+                         ($this->arg('tags')) ? $this->arg('tags') : implode(' ', $tags),
+                         _('Tags for this user (letters, numbers, -, ., and _), comma- or space- separated'));
+            $this->elementEnd('li');
+            $this->elementEnd('ul');
+            $this->submit('save', _('Save'));
+            $this->elementEnd('fieldset');
+            $this->elementEnd('form');
+
+            Event::handle('EndShowTagProfileForm', array($this, $this->profile));
+        }
+    }
+
+    function saveTags()
+    {
+        $id = $this->trimmed('id');
+        $tagstring = $this->trimmed('tags');
+        $token = $this->trimmed('token');
+
+        if (Event::handle('StartSavePeopletags', array($this, $tagstring))) {
+            if (!$token || $token != common_session_token()) {
+                $this->showForm(_('There was a problem with your session token. '.
+                                  'Try again, please.'));
+                return;
+            }
+
+            $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)) {
+                        $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
+                        return;
+                    }
+
+                    $tag_priv[$tag] = $private;
+                }
+            }
+
+            $user = common_current_user();
+
+            try {
+                $result = Profile_tag::setTags($user->id, $this->profile->id, $tags, $tag_priv);
+                if (!$result) {
+                    throw new Exception('The tags could not be saved.');
+                }
+            } catch (Exception $e) {
+                $this->showForm($e->getMessage());
+                return false;
+            }
+
+            if ($this->boolean('ajax')) {
+                $this->startHTML('text/xml;charset=utf-8');
+                $this->elementStart('head');
+                $this->element('title', null, _('Tags'));
+                $this->elementEnd('head');
+                $this->elementStart('body');
+
+                if ($user->id == $this->profile->id) {
+                    $widget = new SelftagsWidget($this, $user, $this->profile);
+                    $widget->show();
+                } else {
+                    $widget = new PeopletagsWidget($this, $user, $this->profile);
+                    $widget->show();
+                }
+
+                $this->elementEnd('body');
+                $this->elementEnd('html');
+            } else {
+                $this->error = 'Tags saved.';
+                $this->showForm();
+            }
+
+            Event::handle('EndSavePeopletags', array($this, $tagstring));
+        }
+    }
+
+    function showPageNotice()
+    {
+        if ($this->error) {
+            $this->element('p', 'error', $this->error);
+        } else {
+            $this->elementStart('div', 'instructions');
+            $this->element('p', null,
+                           _('Use this form to add tags to your subscribers or subscriptions.'));
+            $this->elementEnd('div');
+        }
+    }
+}
+
diff --git a/actions/unsubscribepeopletag.php b/actions/unsubscribepeopletag.php
new file mode 100644 (file)
index 0000000..a912cc1
--- /dev/null
@@ -0,0 +1,142 @@
+<?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()) {
+            $this->clientError(_('You must be logged in to unsubscribe to a peopletag.'));
+            return false;
+        }
+        // Only allow POST requests
+
+        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+            $this->clientError(_('This action only accepts POST requests.'));
+            return false;
+        }
+
+        // CSRF protection
+
+        $token = $this->trimmed('token');
+
+        if (!$token || $token != common_session_token()) {
+            $this->clientError(_('There was a problem with your session token.'.
+                                 ' Try again, please.'));
+            return false;
+        }
+
+        $tagger_arg = $this->trimmed('tagger');
+        $tag_arg = $this->trimmed('tag');
+
+        $id = intval($this->arg('id'));
+        if ($id) {
+            $this->peopletag = Profile_list::staticGet('id', $id);
+        } else {
+            $this->clientError(_('No ID given.'), 404);
+            return false;
+        }
+
+        if (!$this->peopletag || $this->peopletag->private) {
+            $this->clientError(_('No such peopletag.'), 404);
+            return false;
+        }
+
+        $this->tagger = Profile::staticGet('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');
+            $this->element('title', null, sprintf(_('%1$s unsubscribed to peopletag %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->elementEnd('html');
+        } else {
+            if (common_get_returnto()) {
+                common_redirect(common_get_returnto(), 303);
+                return true;
+            }
+            common_redirect(common_local_url('peopletagsbyuser',
+                                array('nickname' => $this->tagger->nickname)),
+                            303);
+        }
+    }
+}
index 31e52dfcf26af0c713403949e89c5a5a49565bbd..80b31762538d34063fdf897a592411d5a174c005 100644 (file)
@@ -291,6 +291,8 @@ class Action extends HTMLOutputter // lawsuit
                 $this->script('jquery.cookie.min.js');
                 $this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.min.js').'"); }');
                 $this->script('jquery.joverlay.min.js');
+                $this->inlineScript('function _loadTagInput(init) { $.getScript("'.common_path('js/jquery.timers.js'). '"); $.getScript("'.common_path('js/jquery.tagInput.js').'", init); } var _peopletagAC = "' . common_local_url('peopletagautocomplete') . '";');
+
                 Event::handle('EndShowJQueryScripts', array($this));
             }
             if (Event::handle('StartShowStatusNetScripts', array($this)) &&
index ee1e4cd84976c4af68cb57af70a3ee6f26d6ff5d..7f17f2d0a5145f683e398a47a781be60e842e8ab 100644 (file)
@@ -227,7 +227,9 @@ class Router
             $m->connect('main/sup/:seconds', array('action' => 'sup'),
                         array('seconds' => '[0-9]+'));
 
-            $m->connect('main/tagother/:id', array('action' => 'tagother'));
+            $m->connect('main/tagprofile', array('action' => 'tagprofile'));
+            $m->connect('main/tagprofile/:id', array('action' => 'tagprofile'),
+                                               array('id' => '[0-9]+'));
 
             $m->connect('main/oembed',
                         array('action' => 'oembed'));
@@ -355,10 +357,6 @@ class Router
                         array('action' => 'tag'),
                         array('tag' => self::REGEX_TAG));
 
-            $m->connect('peopletag/:tag',
-                        array('action' => 'peopletag'),
-                        array('tag' => self::REGEX_TAG));
-
             // groups
 
             $m->connect('group/new', array('action' => 'newgroup'));
@@ -959,6 +957,76 @@ class Router
                                 array('nickname' => Nickname::DISPLAY_FMT));
                 }
 
+                // people tags
+
+                $m->connect('peopletags', array('action' => 'publicpeopletagcloud'));
+
+                $m->connect('peopletag/:tag', array('action' => 'peopletag',
+                                                    'tag'    => self::REGEX_TAG));
+
+                $m->connect('selftag/:tag', array('action' => 'selftag',
+                                                  'tag'    => self::REGEX_TAG));
+
+                $m->connect('main/addpeopletag', array('action' => 'addpeopletag'));
+
+                $m->connect('main/removepeopletag', array('action' => 'removepeopletag'));
+
+                $m->connect('main/profilecompletion', array('action' => 'profilecompletion'));
+
+                $m->connect('main/peopletagautocomplete', array('action' => 'peopletagautocomplete'));
+
+                $m->connect(':nickname/peopletags',
+                                array('action' => 'peopletagsbyuser',
+                                      'nickname' => Nickname::DISPLAY_FMT));
+
+                $m->connect(':nickname/peopletags/private',
+                                array('action' => 'peopletagsbyuser',
+                                      'nickname' => Nickname::DISPLAY_FMT,
+                                      'private' => 1));
+
+                $m->connect(':nickname/peopletags/public',
+                                array('action' => 'peopletagsbyuser',
+                                      'nickname' => Nickname::DISPLAY_FMT,
+                                      'public' => 1));
+
+                $m->connect(':nickname/othertags',
+                                array('action' => 'peopletagsforuser',
+                                      'nickname' => Nickname::DISPLAY_FMT));
+
+                $m->connect(':nickname/peopletagsubscriptions',
+                                array('action' => 'peopletagsubscriptions',
+                                      'nickname' => Nickname::DISPLAY_FMT));
+
+                $m->connect(':tagger/all/:tag/subscribers',
+                                array('action' => 'peopletagsubscribers',
+                                      'tagger' => Nickname::DISPLAY_FMT,
+                                      'tag' => self::REGEX_TAG));
+
+                $m->connect(':tagger/all/:tag/tagged',
+                                array('action' => 'peopletagged',
+                                      'tagger' => Nickname::DISPLAY_FMT,
+                                      'tag' => self::REGEX_TAG));
+
+                $m->connect(':tagger/all/:tag/edit',
+                                array('action' => 'editpeopletag',
+                                      'tagger' => Nickname::DISPLAY_FMT,
+                                      'tag' => self::REGEX_TAG));
+
+                foreach(array('subscribe', 'unsubscribe') as $v) {
+                    $m->connect('peopletag/:id/'.$v,
+                                    array('action' => $v.'peopletag',
+                                          'id' => '[0-9]{1,64}'));
+                }
+                $m->connect('user/:tagger_id/profiletag/:id/id',
+                                array('action' => 'profiletagbyid',
+                                      'tagger_id' => '[0-9]+',
+                                      'id' => '[0-9]+'));
+
+                $m->connect(':tagger/all/:tag',
+                                array('action' => 'showprofiletag',
+                                      'tagger' => Nickname::DISPLAY_FMT,
+                                      'tag' => self::REGEX_TAG));
+
                 foreach (array('subscriptions', 'subscribers') as $a) {
                     $m->connect(':nickname/'.$a.'/:tag',
                                 array('action' => $a),