Merge branch 'people_tags_rebase' into 1.0.x
Conflicts: EVENTS.txt
This commit is contained in:
commit
e75c9988eb
153
EVENTS.txt
153
EVENTS.txt
@ -1116,6 +1116,156 @@ EndGroupProfileElements: Start showing stuff about the group on its profile page
|
||||
- $action: action being executed (for output and params)
|
||||
- $group: group for the page
|
||||
|
||||
StartShowProfileTagContent: When showing a people tag page
|
||||
- $action: action being executed (for output and params)
|
||||
|
||||
EndShowProfileTagContent: After showing the contents of a people tag page
|
||||
- $action: action being executed (for output and params)
|
||||
|
||||
StartShowTaggedProfilesMiniList: at the start of mini list of tagged profiles
|
||||
- $action: action being executed (for output and params)
|
||||
|
||||
EndShowTaggedProfilesMiniList: at the end of mini list of tagged profiles
|
||||
- $action: action being executed (for output and params)
|
||||
|
||||
StartShowProfileTagSubscribersMiniList: at the start of mini list of people tag subscribers
|
||||
- $action: action being executed (for output and params)
|
||||
|
||||
EndShowProfileTagSubscribersMiniList: at the end of mini list of people tag subscribers
|
||||
- $action: action being executed (for output and params)
|
||||
|
||||
StartTagProfileAction: When starting to show profile tagging page
|
||||
- $action: action being executed (for output and params)
|
||||
- $profile: profile being tagged
|
||||
|
||||
EndTagProfileAction: After showing profile tagging page
|
||||
- $action: action being executed (for output and params)
|
||||
- $profile: profile being tagged
|
||||
|
||||
StartProfileCompletionSearch: When starting a profile search for autocompletion
|
||||
- $action: action being executed (for output and params)
|
||||
- &$profile: result Profile objects
|
||||
- $search_engine: the search engine
|
||||
|
||||
EndProfileCompletionSearch: After search results for profile autocompletion have been found
|
||||
- $action: profilec completion action
|
||||
- &$profile: current result Profile objects
|
||||
- $search_engine: The search engine object
|
||||
|
||||
StartShowTagProfileForm: When showing people tagging form
|
||||
- $action: action being executed (for output and params)
|
||||
- $profile: profile being tagged
|
||||
|
||||
EndShowTagProfileForm: After showing people tagging form
|
||||
- $action: action being executed (for output and params)
|
||||
- $profile: profile being tagged
|
||||
|
||||
StartSavePeopletags: When starting to save people tags
|
||||
- $action: action being executed (for output and params)
|
||||
- $tagstring: string input, a list of tags
|
||||
|
||||
EndSavePeopletags: After saving people tags
|
||||
- $action: action being executed (for output and params)
|
||||
- $tagstring: string input, a list of tags
|
||||
|
||||
StartProfiletagGetUri: when generating the Uri for a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$uri: the URI
|
||||
|
||||
EndProfiletagGetUri: after generating the uri for a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$uri: the URI
|
||||
|
||||
StartUserPeopletagHomeUrl: when generating the homepage url for a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$url: the URL
|
||||
|
||||
EndUserPeopletagHomeUrl: after generating the homepage url for a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$url: the URL
|
||||
|
||||
StartProfiletagPermalink: when generating the permalink url for a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$url: the URL
|
||||
|
||||
EndProfiletagPermalink: after generating the permalink url for a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$url: the URL
|
||||
|
||||
StartTagProfile: when tagging a profile
|
||||
- $tagger: profile tagging
|
||||
- $tagged: profile being tagged
|
||||
- $tag: the tag
|
||||
|
||||
EndTagProfile: after tagging a profile
|
||||
- $newtag: the newly created Profile_tag object
|
||||
|
||||
StartUntagProfile: when deleting a people tag
|
||||
- $ptag: the Profile_tag object being deleted
|
||||
|
||||
EndUntagProfile: after deleting a people tag
|
||||
- $orig: a copy of the deleted Profile_tag object
|
||||
|
||||
StartSubscribePeopletag: when subscribing to a people tag
|
||||
- $peopletag: Profile_list object being subscribed to
|
||||
- $profile: subscriber's profile
|
||||
|
||||
EndSubscribePeopletag: after subscribing to a people tag
|
||||
- $profile_list: the people tag, a Profile_list object: Profile_list object being subscribed to
|
||||
- $profile: subscriber's profile
|
||||
|
||||
StartUnsubscribePeopletag: when unsubscribing to a people tag
|
||||
- $profile_list: the people tag, a Profile_list object: Profile_list object being subscribed to
|
||||
- $profile: subscriber's profile
|
||||
|
||||
EndUnsubscribePeopletag: after unsubscribing to a people tag
|
||||
- $peopletag: Profile_list object being subscribed to
|
||||
- $profile: subscriber's profile
|
||||
|
||||
StartActivityObjectFromPeopletag: while starting to create an ActivityObject from a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$object: activity object
|
||||
|
||||
EndActivityObjectFromPeopletag: after making an ActivityObject from a people tag
|
||||
- $profile_list: the people tag, a Profile_list object
|
||||
- &$object: activity object
|
||||
|
||||
StartPeopletagGroupNav: Showing the people tag nav menu
|
||||
- $menu: the menu widget; use $menu->action for output
|
||||
|
||||
EndPeopletagGroupNav: after showing the people tag nav menu
|
||||
- $menu: the menu widget; use $menu->action for output
|
||||
|
||||
StartShowPeopletagItem: when showing a people tag
|
||||
- $widget: PeopletagListItem widget
|
||||
|
||||
EndShowPeopletagItem: after showing a people tag
|
||||
- $widget: PeopletagListItem widget
|
||||
|
||||
StartSubscribePeopletagForm: when showing people tag subscription form
|
||||
- $action: action being executed (for output and params)
|
||||
- $peopletag: people tag being subscribed to
|
||||
|
||||
EndSubscribePeopletagForm: after showing the people tag subscription form
|
||||
- $action: action being executed (for output and params)
|
||||
- $peopletag: people tag being subscribed to
|
||||
|
||||
StartShowPeopletags: when showing a textual list of people tags
|
||||
- $widget: PeopletagsWidget; use $widget->out for output
|
||||
- $tagger: profile of the tagger
|
||||
- $tagged: profile tagged
|
||||
|
||||
EndShowPeopletags: after showing a textual list of people tags
|
||||
- $widget: PeopletagsWidget; use $widget->out for output
|
||||
- $tagger: profile of the tagger
|
||||
- $tagged: profile tagged
|
||||
|
||||
StartProfileListItemTags: when showing people tags in a profile list item widget
|
||||
- $widget: ProfileListItem widget
|
||||
|
||||
EndProfileListItemTags: after showing people tags in a profile list item widget
|
||||
- $widget: ProfileListItem widget
|
||||
|
||||
StartActivityObjectOutputAtom: Called at start of Atom XML output generation for ActivityObject chunks, just inside the <activity:object>. Cancel the event to take over its output completely (you're responsible for calling the matching End event if so)
|
||||
- $obj: ActivityObject
|
||||
- $out: XMLOutputter to append custom output
|
||||
@ -1160,7 +1310,7 @@ StartShowGroupProfileBlock: When showing the profile block for a group
|
||||
- $out: XMLOutputter to append custom output
|
||||
- $profile: the profile being shown
|
||||
|
||||
EndShowGroupProfileBlock: After showing showing the profile block for a group
|
||||
EndShowGroupProfileBlock: After showing the profile block for a group
|
||||
- $out: XMLOutputter to append custom output
|
||||
- $group: the group being shown
|
||||
|
||||
@ -1183,3 +1333,4 @@ EndShowThreadedNoticeSub: when showing a reply to a notice
|
||||
- $nli: parent noticelistitem
|
||||
- $parent: parent notice
|
||||
- $child: child notice
|
||||
|
||||
|
172
actions/addpeopletag.php
Normal file
172
actions/addpeopletag.php
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
275
actions/apilist.php
Normal file
275
actions/apilist.php
Normal file
@ -0,0 +1,275 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show, update or delete a list.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author 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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
class ApiListAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* The list in question in the current request
|
||||
*/
|
||||
|
||||
var $list = null;
|
||||
|
||||
/**
|
||||
* Is this an update request?
|
||||
*/
|
||||
|
||||
var $update = false;
|
||||
|
||||
/**
|
||||
* Is this a delete request?
|
||||
*/
|
||||
|
||||
var $delete = false;
|
||||
|
||||
/**
|
||||
* Set the flags for handling the request. Show list if this is a GET
|
||||
* request, update it if it is POST, delete list if method is DELETE
|
||||
* or if method is POST and an argument _method is set to DELETE. Act
|
||||
* like we don't know if the current user has no access to the list.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* - id: the id of the tag or the tag itself
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->delete = ($_SERVER['REQUEST_METHOD'] == 'DELETE' ||
|
||||
($this->trimmed('_method') == 'DELETE' &&
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST'));
|
||||
|
||||
// update list if method is POST or PUT and $this->delete is not true
|
||||
$this->update = (!$this->delete &&
|
||||
in_array($_SERVER['REQUEST_METHOD'], array('POST', 'PUT')));
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
$this->clientError(_('Not found'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if($this->delete) {
|
||||
$this->handleDelete();
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->update) {
|
||||
$this->handlePut();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* require authentication if it is a write action or user is ambiguous
|
||||
*
|
||||
*/
|
||||
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function handlePut()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
$this->clientError(
|
||||
_('You can not update lists that don\'t belong to you.'),
|
||||
401,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
$new_list = clone($this->list);
|
||||
$new_list->tag = common_canonical_tag($this->arg('name'));
|
||||
$new_list->description = common_canonical_tag($this->arg('description'));
|
||||
$new_list->private = ($this->arg('mode') === 'private') ? true : false;
|
||||
|
||||
$result = $new_list->update($this->list);
|
||||
|
||||
if(!$result) {
|
||||
$this->clientError(
|
||||
_('An error occured.'),
|
||||
503,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($new_list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($new_list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function handleDelete()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
$this->clientError(
|
||||
_('You can not delete lists that don\'t belong to you.'),
|
||||
401,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
$record = clone($this->list);
|
||||
$this->list->delete();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($record);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($record);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that this resource is not read-only.
|
||||
*
|
||||
* @return boolean is_read-only=false
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was the list (people tag) last updated?
|
||||
*
|
||||
* @return String time_last_modified
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if(!empty($this->list)) {
|
||||
return strtotime($this->list->modified);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->list)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->list->created),
|
||||
strtotime($this->list->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
124
actions/apilistmember.php
Normal file
124
actions/apilistmember.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* API method to check if a user belongs to a list.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author 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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
/**
|
||||
* Action handler for Twitter list_memeber methods
|
||||
*
|
||||
* @category API
|
||||
* @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/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
|
||||
class ApiListMemberAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Set the flags for handling the request. Show the profile if this
|
||||
* is a GET request AND the profile is a member of the list, add a member
|
||||
* if it is a POST, remove the profile from the list if method is DELETE
|
||||
* or if method is POST and an argument _method is set to DELETE. Act
|
||||
* like we don't know if the current user has no access to the list.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* - list_id: the id of the tag or the tag itself
|
||||
* - id: the id of the member being looked for/added/removed
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
$this->clientError(_('Not found'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$arr = array('tagger' => $this->list->tagger,
|
||||
'tag' => $this->list->tag,
|
||||
'tagged' => $this->user->id);
|
||||
$ptag = Profile_tag::pkeyGet($arr);
|
||||
|
||||
if(empty($ptag)) {
|
||||
$this->clientError(
|
||||
_('The specified user is not a member of this list'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
$user = $this->twitterUserArray($this->user->getProfile(), true);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUser($user, 'user', true);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonUser($user);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
173
actions/apilistmembers.php
Normal file
173
actions/apilistmembers.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List/add/remove list members.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author 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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apilistusers.php';
|
||||
|
||||
class ApiListMembersAction extends ApiListUsersAction
|
||||
{
|
||||
/**
|
||||
* Add a user to a list (tag someone)
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
$this->clientError(
|
||||
_('You aren\'t allowed to add members to this list'),
|
||||
401,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->user === false) {
|
||||
$this->clientError(
|
||||
_('You must specify a member'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = Profile_tag::setTag($this->auth_user->id,
|
||||
$this->user->id, $this->list->tag);
|
||||
|
||||
if(empty($result)) {
|
||||
$this->clientError(
|
||||
_('An error occured.'),
|
||||
500,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user from a list (untag someone)
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function handleDelete()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
$this->clientError(
|
||||
_('You aren\'t allowed to remove members from this list'),
|
||||
401,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->user === false) {
|
||||
$this->clientError(
|
||||
_('You must specify a member'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$args = array('tagger' => $this->auth_user->id,
|
||||
'tagged' => $this->user->id,
|
||||
'tag' => $this->list->tag);
|
||||
$ptag = Profile_tag::pkeyGet($args);
|
||||
|
||||
if(empty($ptag)) {
|
||||
$this->clientError(
|
||||
_('The user you are trying to remove from the list is not a member'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $ptag->delete();
|
||||
|
||||
if(empty($result)) {
|
||||
$this->clientError(
|
||||
_('An error occured.'),
|
||||
500,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the members of a list (people tagged)
|
||||
*/
|
||||
|
||||
function getUsers()
|
||||
{
|
||||
$fn = array($this->list, 'getTagged');
|
||||
list($this->users, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
136
actions/apilistmemberships.php
Normal file
136
actions/apilistmemberships.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get a list of lists a user belongs to. (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 API
|
||||
* @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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
/**
|
||||
* Action handler for API method to list lists a user belongs to.
|
||||
* (people tags for a user)
|
||||
*
|
||||
* @category API
|
||||
* @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/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
|
||||
class ApiListMembershipsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = array();
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
|
||||
/**
|
||||
* Prepare for running the action
|
||||
* Take arguments for running:s
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user.'), 404, $this->format);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->getLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the lists
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$fn = array($profile, 'getOtherTags');
|
||||
|
||||
# 20 lists
|
||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array($this->auth_user), $this->cursor, 20);
|
||||
}
|
||||
}
|
244
actions/apilists.php
Normal file
244
actions/apilists.php
Normal file
@ -0,0 +1,244 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List existing lists or create a new list.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author 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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
/**
|
||||
* Action handler for Twitter list_memeber methods
|
||||
*
|
||||
* @category API
|
||||
* @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/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
|
||||
class ApiListsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = null;
|
||||
var $cursor = 0;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $create = false;
|
||||
|
||||
/**
|
||||
* Set the flags for handling the request. List lists created by user if this
|
||||
* is a GET request, create a new list if it is a POST request.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* Parameters for POST request
|
||||
* - name: name of the new list (the people tag itself)
|
||||
* - mode: (optional) mode for the new list private/public
|
||||
* - description: (optional) description for the list
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->create = ($_SERVER['REQUEST_METHOD'] == 'POST');
|
||||
|
||||
if (!$this->create) {
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user.'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
$this->getLists();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* require authentication if it is a write action or user is ambiguous
|
||||
*
|
||||
*/
|
||||
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request:
|
||||
* Show the lists the user has created if the request method is GET
|
||||
* Create a new list by diferring to handlePost() if it is POST.
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if($this->create) {
|
||||
return $this->handlePost();
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
$name=$this->arg('name');
|
||||
if(empty($name)) {
|
||||
// mimick twitter
|
||||
print _("A list's name can't be blank.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// twitter creates a new list by appending a number to the end
|
||||
// if the list by the given name already exists
|
||||
// it makes more sense to return the existing list instead
|
||||
|
||||
$private = null;
|
||||
if ($this->arg('mode') === 'public') {
|
||||
$private = false;
|
||||
} else if ($this->arg('mode') === 'private') {
|
||||
$private = true;
|
||||
}
|
||||
|
||||
$list = Profile_list::ensureTag($this->auth_user->id,
|
||||
$this->arg('name'),
|
||||
$this->arg('description'),
|
||||
$private);
|
||||
if (empty($list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lists
|
||||
*/
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$cursor = (int) $this->arg('cursor', -1);
|
||||
|
||||
// twitter fixes count at 20
|
||||
// there is no argument named count
|
||||
$count = 20;
|
||||
$profile = $this->user->getProfile();
|
||||
$fn = array($profile, 'getOwnedTags');
|
||||
|
||||
list($this->lists,
|
||||
$this->next_cursor,
|
||||
$this->prev_cursor) = Profile_list::getAtCursor($fn, array($this->auth_user), $cursor, $count);
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!$this->create && !empty($this->lists) && (count($this->lists) > 0)) {
|
||||
return strtotime($this->lists[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of lists
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
if (!$this->create && !empty($this->lists) && (count($this->lists) > 0)) {
|
||||
|
||||
$last = count($this->lists) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->lists[0]->created),
|
||||
strtotime($this->lists[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
91
actions/apilistsubscriber.php
Normal file
91
actions/apilistsubscriber.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check if a user is subscribed to a list
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
|
||||
class ApiListSubscriberAction extends ApiBareAuthAction
|
||||
{
|
||||
var $list = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
$this->clientError(_('Not found'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$arr = array('profile_tag_id' => $this->list->id,
|
||||
'profile_id' => $this->user->id);
|
||||
$sub = Profile_tag_subscription::pkeyGet($arr);
|
||||
|
||||
if(empty($sub)) {
|
||||
$this->clientError(
|
||||
_('The specified user is not a subscriber of this list'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
$user = $this->twitterUserArray($this->user->getProfile(), true);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUser($user, 'user', true);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonUser($user);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
125
actions/apilistsubscribers.php
Normal file
125
actions/apilistsubscribers.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show/add/remove list 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 API
|
||||
* @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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apilistusers.php';
|
||||
|
||||
class ApiListSubscribersAction extends ApiListUsersAction
|
||||
{
|
||||
/**
|
||||
* Subscribe to list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
$result = Profile_tag_subscription::add($this->list,
|
||||
$this->auth_user);
|
||||
|
||||
if(empty($result)) {
|
||||
$this->clientError(
|
||||
_('An error occured.'),
|
||||
500,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function handleDelete()
|
||||
{
|
||||
$args = array('profile_tag_id' => $this->list->id,
|
||||
'profile_id' => $this->auth_user->id);
|
||||
$ptag = Profile_tag_subscription::pkeyGet($args);
|
||||
|
||||
if(empty($ptag)) {
|
||||
$this->clientError(
|
||||
_('You are not subscribed to this list'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Profile_tag_subscription::remove($this->list, $this->auth_user);
|
||||
|
||||
if(empty($result)) {
|
||||
$this->clientError(
|
||||
_('An error occured.'),
|
||||
500,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getUsers()
|
||||
{
|
||||
$fn = array($this->list, 'getSubscribers');
|
||||
list($this->users, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
126
actions/apilistsubscriptions.php
Normal file
126
actions/apilistsubscriptions.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get a list of lists a user is subscribed to.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
class ApiListSubscriptionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = array();
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
$this->getLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the lists
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user.'), 404, $this->format);
|
||||
return;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLists()
|
||||
{
|
||||
if(empty($this->user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$fn = array($profile, 'getTagSubscriptions');
|
||||
# 20 lists
|
||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
266
actions/apitimelinelist.php
Normal file
266
actions/apitimelinelist.php
Normal file
@ -0,0 +1,266 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a list's notices
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiprivateauth.php';
|
||||
require_once INSTALLDIR . '/lib/atomlistnoticefeed.php';
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted to the list specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiTimelineListAction extends ApiPrivateAuthAction
|
||||
{
|
||||
|
||||
var $list = null;
|
||||
var $notices = array();
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $cursor = -1;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (empty($this->list)) {
|
||||
$this->clientError(_('List not found.'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->getNotices();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showTimeline()
|
||||
{
|
||||
// We'll pull common formatting out of this for other formats
|
||||
$atom = new AtomListNoticeFeed($this->list, $this->auth_user);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('statuses_list',
|
||||
array('xmlns:statusnet' => 'http://status.net/schema/api/1/'));
|
||||
$this->elementStart('statuses', array('type' => 'array'));
|
||||
|
||||
foreach ($this->notices as $n) {
|
||||
$twitter_status = $this->twitterStatusArray($n);
|
||||
$this->showTwitterXmlStatus($twitter_status);
|
||||
}
|
||||
|
||||
$this->elementEnd('statuses');
|
||||
$this->element('next_cursor', null, $this->next_cursor);
|
||||
$this->element('previous_cursor', null, $this->prev_cursor);
|
||||
$this->elementEnd('statuses_list');
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$this->list->getUri(),
|
||||
$atom->subtitle,
|
||||
null,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
try {
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
} catch (Atom10FeedException $e) {
|
||||
$this->serverError(
|
||||
'Could not generate feed for list - ' . $e->getMessage()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
|
||||
$statuses = array();
|
||||
foreach ($this->notices as $n) {
|
||||
$twitter_status = $this->twitterStatusArray($n);
|
||||
array_push($statuses, $twitter_status);
|
||||
}
|
||||
|
||||
$statuses_list = array('statuses' => $statuses,
|
||||
'next_cursor' => $this->next_cusror,
|
||||
'next_cursor_str' => strval($this->next_cusror),
|
||||
'previous_cursor' => $this->prev_cusror,
|
||||
'previous_cursor_str' => strval($this->prev_cusror)
|
||||
);
|
||||
$this->showJsonObjects($statuses_list);
|
||||
|
||||
$this->initDocument('json');
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
|
||||
function getNotices()
|
||||
{
|
||||
$fn = array($this->list, 'getNotices');
|
||||
list($this->notices, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
if (!$this->notices) {
|
||||
$this->notices = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, list ID and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->list->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
311
actions/editpeopletag.php
Normal file
311
actions/editpeopletag.php
Normal file
@ -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 showObjectNav()
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
@ -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
|
||||
*
|
||||
@ -16,13 +16,16 @@
|
||||
* 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,150 +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)) {
|
||||
// TRANS: Client error displayed when trying to tag a profile with an invalid tag.
|
||||
// TRANS: %s is the invalid tag.
|
||||
$this->clientError(sprintf(_('Not a valid people tag: %s.'),
|
||||
$this->tag));
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->page = ($this->arg('page')) ? $this->arg('page') : 1;
|
||||
function title()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
|
||||
$tag_arg = $this->arg('tag');
|
||||
$tag = common_canonical_tag($tag_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
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;
|
||||
|
||||
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 handle($args)
|
||||
{
|
||||
parent::handle($argarray);
|
||||
parent::handle($args);
|
||||
$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 showLocalNav()
|
||||
{
|
||||
$nav = new PublicGroupNav($this);
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
function showAnonymousMessage()
|
||||
{
|
||||
$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');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
|
||||
$limit = PEOPLETAGS_PER_PAGE + 1;
|
||||
|
||||
$profile = new Profile();
|
||||
$ptags = new Profile_list();
|
||||
$ptags->tag = $this->tag;
|
||||
|
||||
$offset = ($this->page - 1) * PROFILES_PER_PAGE;
|
||||
$limit = PROFILES_PER_PAGE + 1;
|
||||
$user = common_current_user();
|
||||
|
||||
if (common_config('db', 'type') == 'pgsql') {
|
||||
$lim = ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
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 {
|
||||
$lim = ' LIMIT ' . $offset . ', ' . $limit;
|
||||
$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) )');
|
||||
|
||||
$ptags->orderBy('profile_list.modified DESC');
|
||||
$ptags->find();
|
||||
}
|
||||
|
||||
// XXX: memcached this
|
||||
$pl = new PeopletagList($ptags, $this);
|
||||
$cnt = $pl->show();
|
||||
|
||||
$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));
|
||||
$this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
|
||||
$this->page, 'peopletag', array('tag' => $this->tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
function title()
|
||||
function showSections()
|
||||
{
|
||||
// TRANS: Page title for users with a certain self-tag.
|
||||
// TRANS: %1$s is the tag, %2$s is the page number.
|
||||
return sprintf(_('Users self-tagged with %1$s - page %2$d'),
|
||||
$this->tag, $this->page);
|
||||
}
|
||||
}
|
||||
|
||||
class PeopleTagList extends ProfileList
|
||||
{
|
||||
function newListItem($profile)
|
||||
{
|
||||
return new PeopleTagListItem($profile, $this->action);
|
||||
}
|
||||
}
|
||||
|
||||
class PeopleTagListItem extends ProfileListItem
|
||||
{
|
||||
function linkAttributes()
|
||||
{
|
||||
$aAttrs = parent::linkAttributes();
|
||||
|
||||
if (common_config('nofollow', 'peopletag')) {
|
||||
$aAttrs['rel'] .= ' nofollow';
|
||||
}
|
||||
|
||||
return $aAttrs;
|
||||
}
|
||||
|
||||
function homepageAttributes()
|
||||
{
|
||||
$aAttrs = parent::linkAttributes();
|
||||
|
||||
if (common_config('nofollow', 'peopletag')) {
|
||||
$aAttrs['rel'] = 'nofollow';
|
||||
}
|
||||
|
||||
return $aAttrs;
|
||||
}
|
||||
}
|
||||
|
127
actions/peopletagautocomplete.php
Normal file
127
actions/peopletagautocomplete.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?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;
|
||||
var $tags;
|
||||
var $last_mod;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$tags = $profile->getOwnedTags(common_current_user());
|
||||
|
||||
$this->tags = array();
|
||||
while ($tags->fetch()) {
|
||||
|
||||
if (empty($this->last_mod)) {
|
||||
$this->last_mod = $tags->modified;
|
||||
}
|
||||
|
||||
$arr = array();
|
||||
$arr['tag'] = $tags->tag;
|
||||
$arr['mode'] = $tags->private ? 'private' : 'public';
|
||||
// $arr['url'] = $tags->homeUrl();
|
||||
$arr['freq'] = $tags->taggedCount();
|
||||
|
||||
$this->tags[] = $arr;
|
||||
}
|
||||
|
||||
$tags->free();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last modified time
|
||||
*
|
||||
* Helps in browser-caching
|
||||
*
|
||||
* @return String time
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
return strtotime($this->last_mod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request
|
||||
*
|
||||
* Print the JSON autocomplete data
|
||||
*
|
||||
* @param Array $args unused.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
//common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($this->tags));
|
||||
if ($this->tags) {
|
||||
print(json_encode($this->tags));
|
||||
exit(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
223
actions/peopletagged.php
Normal file
223
actions/peopletagged.php
Normal file
@ -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;
|
||||
}
|
||||
}
|
253
actions/peopletagsbyuser.php
Normal file
253
actions/peopletagsbyuser.php
Normal file
@ -0,0 +1,253 @@
|
||||
<?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 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"
|
||||
}
|
||||
}
|
164
actions/peopletagsforuser.php
Normal file
164
actions/peopletagsforuser.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?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 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"
|
||||
}
|
||||
}
|
238
actions/peopletagsubscribers.php
Normal file
238
actions/peopletagsubscribers.php
Normal file
@ -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;
|
||||
}
|
||||
}
|
132
actions/peopletagsubscriptions.php
Normal file
132
actions/peopletagsubscriptions.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?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 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"
|
||||
}
|
||||
}
|
214
actions/profilecompletion.php
Normal file
214
actions/profilecompletion.php
Normal file
@ -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');
|
||||
}
|
||||
}
|
@ -298,19 +298,25 @@ class ProfilesettingsAction extends SettingsAction
|
||||
return;
|
||||
}
|
||||
|
||||
if ($tagstring) {
|
||||
$tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $tagstring));
|
||||
} else {
|
||||
$tags = array();
|
||||
}
|
||||
$tag_priv = array();
|
||||
if (is_string($tagstring) && strlen($tagstring) > 0) {
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$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));
|
||||
$this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
|
||||
return;
|
||||
}
|
||||
|
||||
$tag_priv[$tag] = $private;
|
||||
}
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
@ -444,7 +450,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.
|
||||
|
92
actions/profiletagbyid.php
Normal file
92
actions/profiletagbyid.php
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -223,6 +223,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();
|
||||
}
|
||||
|
173
actions/publicpeopletagcloud.php
Normal file
173
actions/publicpeopletagcloud.php
Normal file
@ -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');
|
||||
}
|
||||
}
|
173
actions/removepeopletag.php
Normal file
173
actions/removepeopletag.php
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
205
actions/selftag.php
Normal file
205
actions/selftag.php
Normal file
@ -0,0 +1,205 @@
|
||||
<?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)) {
|
||||
// TRANS: Client error displayed when trying to tag a profile with an invalid tag.
|
||||
// TRANS: %s is the invalid 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();
|
||||
}
|
||||
}
|
||||
}
|
354
actions/showprofiletag.php
Normal file
354
actions/showprofiletag.php
Normal file
@ -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 showObjectNav()
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
144
actions/subscribepeopletag.php
Normal file
144
actions/subscribepeopletag.php
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,237 +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');
|
||||
|
||||
// @todo FIXME: documentation missing.
|
||||
class TagotherAction extends Action
|
||||
{
|
||||
var $profile = null;
|
||||
var $error = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
||||
$this->clientError(_('Not logged in.'), 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
if (!$id) {
|
||||
// TRANS: Client error displayed on user tag page when trying to add tags without providing a user ID.
|
||||
$this->clientError(_('No ID argument.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->profile = Profile::staticGet('id', $id);
|
||||
|
||||
if (!$this->profile) {
|
||||
// TRANS: Client error displayed on user tag page when trying to add tags providing a non-existing user ID.
|
||||
$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()
|
||||
{
|
||||
// TRANS: Title for "tag other users" page.
|
||||
// TRANS: %s is the user nickname.
|
||||
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');
|
||||
// TRANS: Header for user details on "tag other users" page.
|
||||
$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');
|
||||
// TRANS: Fieldset legend on "tag other users" page.
|
||||
$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');
|
||||
// TRANS: Field label for inputting tags on "tag other users" page.
|
||||
$this->input('tags', _('Tags'),
|
||||
($this->arg('tags')) ? $this->arg('tags') : implode(' ', Profile_tag::getTags($user->id, $this->profile->id)),
|
||||
// TRANS: Title for input field for inputting tags on "tag other users" page.
|
||||
_('Tags for this user (letters, numbers, -, ., and _), separated by commas or spaces.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
// TRANS: Button text for saving tags for other users.
|
||||
$this->submit('save', _m('BUTTON','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()) {
|
||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
||||
$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)) {
|
||||
// TRANS: Form validation error when entering an invalid tag.
|
||||
// TRANS: %s is the invalid 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)))
|
||||
{
|
||||
// TRANS: Client error on "tag other users" page when tagging a user is not possible because of missing mutual subscriptions.
|
||||
$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) {
|
||||
// TRANS: Client error on "tag other users" page when saving tags fails server side.
|
||||
$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');
|
||||
// TRANS: Title of "tag other users" page.
|
||||
$this->element('title', null, _m('TITLE','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,
|
||||
// TRANS: Page notice on "tag other users" page.
|
||||
_('Use this form to add tags to your subscribers or subscriptions.'));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
}
|
249
actions/tagprofile.php
Normal file
249
actions/tagprofile.php
Normal file
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
142
actions/unsubscribepeopletag.php
Normal file
142
actions/unsubscribepeopletag.php
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -545,6 +545,12 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
$notice->saveKnownGroups($groups);
|
||||
|
||||
if (isset($peopletags)) {
|
||||
$notice->saveProfileTags($peopletags);
|
||||
} else {
|
||||
$notice->saveProfileTags();
|
||||
}
|
||||
|
||||
if (isset($urls)) {
|
||||
$notice->saveKnownUrls($urls);
|
||||
} else {
|
||||
@ -851,6 +857,7 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
|
||||
$users = $this->getSubscribedUsers();
|
||||
$ptags = $this->getProfileTags();
|
||||
|
||||
// FIXME: kind of ignoring 'transitional'...
|
||||
// we'll probably stop supporting inboxless mode
|
||||
@ -874,11 +881,22 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ptags as $ptag) {
|
||||
$users = $ptag->getUserSubscribers();
|
||||
foreach ($users as $id) {
|
||||
if (!array_key_exists($id, $ni)) {
|
||||
$user = User::staticGet('id', $id);
|
||||
if (!$user->hasBlocked($profile)) {
|
||||
$ni[$id] = NOTICE_INBOX_SOURCE_PROFILE_TAG;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
if (!array_key_exists($recipient, $ni)) {
|
||||
$ni[$recipient] = NOTICE_INBOX_SOURCE_REPLY;
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude any deleted, non-local, or blocking recipients.
|
||||
$profile = $this->getProfile();
|
||||
@ -897,6 +915,7 @@ class Notice extends Memcached_DataObject
|
||||
unset($ni[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give plugins a chance to filter out...
|
||||
Event::handle('EndNoticeWhoGets', array($this, &$ni));
|
||||
@ -974,6 +993,39 @@ class Notice extends Memcached_DataObject
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function getProfileTags()
|
||||
{
|
||||
// Don't save ptags for repeats, for now.
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// XXX: cache me
|
||||
|
||||
$ptags = array();
|
||||
|
||||
$ptagi = new Profile_tag_inbox();
|
||||
|
||||
$ptagi->selectAdd();
|
||||
$ptagi->selectAdd('profile_tag_id');
|
||||
|
||||
$ptagi->notice_id = $this->id;
|
||||
|
||||
if ($ptagi->find()) {
|
||||
while ($ptagi->fetch()) {
|
||||
$profile_list = Profile_list::staticGet('id', $ptagi->profile_tag_id);
|
||||
if ($profile_list) {
|
||||
$ptags[] = $profile_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ptagi->free();
|
||||
|
||||
return $ptags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record this notice to the given group inboxes for delivery.
|
||||
* Overrides the regular parsing of !group markup.
|
||||
@ -1086,6 +1138,69 @@ class Notice extends Memcached_DataObject
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* record targets into profile_tag_inbox.
|
||||
* @return array of Profile_list objects
|
||||
*/
|
||||
function saveProfileTags($known=array())
|
||||
{
|
||||
// Don't save ptags for repeats, for now
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if (is_array($known)) {
|
||||
$ptags = $known;
|
||||
} else {
|
||||
$ptags = array();
|
||||
}
|
||||
|
||||
$ptag = new Profile_tag();
|
||||
$ptag->tagged = $this->profile_id;
|
||||
|
||||
if($ptag->find()) {
|
||||
while($ptag->fetch()) {
|
||||
$plist = Profile_list::getByTaggerAndTag($ptag->tagger, $ptag->tag);
|
||||
$ptags[] = clone($plist);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ptags as $target) {
|
||||
$this->addToProfileTagInbox($target);
|
||||
}
|
||||
|
||||
return $ptags;
|
||||
}
|
||||
|
||||
function addToProfileTagInbox($plist)
|
||||
{
|
||||
$ptagi = Profile_tag_inbox::pkeyGet(array('profile_tag_id' => $plist->id,
|
||||
'notice_id' => $this->id));
|
||||
|
||||
if (empty($ptagi)) {
|
||||
|
||||
$ptagi = new Profile_tag_inbox();
|
||||
|
||||
$ptagi->query('BEGIN');
|
||||
$ptagi->profile_tag_id = $plist->id;
|
||||
$ptagi->notice_id = $this->id;
|
||||
$ptagi->created = $this->created;
|
||||
|
||||
$result = $ptagi->insert();
|
||||
if (!$result) {
|
||||
common_log_db_error($ptagi, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Problem saving profile_tag inbox.'));
|
||||
}
|
||||
|
||||
$ptagi->query('COMMIT');
|
||||
|
||||
self::blow('profile_tag:notice_ids:%d', $ptagi->profile_tag_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save reply records indicating that this notice needs to be
|
||||
* delivered to the local users with the given URIs.
|
||||
|
@ -272,6 +272,183 @@ class Profile extends Memcached_DataObject
|
||||
return new ArrayWrapper($groups);
|
||||
}
|
||||
|
||||
function isTagged($peopletag)
|
||||
{
|
||||
$tag = Profile_tag::pkeyGet(array('tagger' => $peopletag->tagger,
|
||||
'tagged' => $this->id,
|
||||
'tag' => $peopletag->tag));
|
||||
return !empty($tag);
|
||||
}
|
||||
|
||||
function canTag($tagged)
|
||||
{
|
||||
if (empty($tagged)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($tagged->id == $this->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$all = common_config('peopletag', 'allow_tagging', 'all');
|
||||
$local = common_config('peopletag', 'allow_tagging', 'local');
|
||||
$remote = common_config('peopletag', 'allow_tagging', 'remote');
|
||||
$subs = common_config('peopletag', 'allow_tagging', 'subs');
|
||||
|
||||
if ($all) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$tagged_user = $tagged->getUser();
|
||||
if (!empty($tagged_user)) {
|
||||
if ($local) {
|
||||
return true;
|
||||
}
|
||||
} else if ($subs) {
|
||||
return (Subscription::exists($this, $tagged) ||
|
||||
Subscription::exists($tagged, $this));
|
||||
} else if ($remote) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getOwnedTags($auth_user, $offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$tags = new Profile_list();
|
||||
$tags->tagger = $this->id;
|
||||
|
||||
if (($auth_user instanceof User || $auth_user instanceof Profile) &&
|
||||
$auth_user->id === $this->id) {
|
||||
// no condition, get both private and public tags
|
||||
} else {
|
||||
$tags->private = false;
|
||||
}
|
||||
|
||||
$tags->selectAdd('id as "cursor"');
|
||||
|
||||
if ($since_id>0) {
|
||||
$tags->whereAdd('id > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$tags->whereAdd('id <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$tags->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$tags->orderBy('id DESC');
|
||||
$tags->find();
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
function getOtherTags($auth_user=null, $offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$lists = new Profile_list();
|
||||
|
||||
$tags = new Profile_tag();
|
||||
$tags->tagged = $this->id;
|
||||
|
||||
$lists->joinAdd($tags);
|
||||
#@fixme: postgres (round(date_part('epoch', my_date)))
|
||||
$lists->selectAdd('unix_timestamp(profile_tag.modified) as "cursor"');
|
||||
|
||||
if ($auth_user instanceof User || $auth_user instanceof Profile) {
|
||||
$lists->whereAdd('( ( profile_list.private = false ) ' .
|
||||
'OR ( profile_list.tagger = ' . $auth_user->id . ' AND ' .
|
||||
'profile_list.private = true ) )');
|
||||
} else {
|
||||
$lists->private = false;
|
||||
}
|
||||
|
||||
if ($since_id>0) {
|
||||
$lists->whereAdd('cursor > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$lists->whereAdd('cursor <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$lists->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$lists->orderBy('profile_tag.modified DESC');
|
||||
$lists->find();
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
function getPrivateTags($offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$tags = new Profile_list();
|
||||
$tags->private = true;
|
||||
$tags->tagger = $this->id;
|
||||
|
||||
if ($since_id>0) {
|
||||
$tags->whereAdd('id > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$tags->whereAdd('id <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$tags->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$tags->orderBy('id DESC');
|
||||
$tags->find();
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
function hasLocalTags()
|
||||
{
|
||||
$tags = new Profile_tag();
|
||||
|
||||
$tags->joinAdd(array('tagger', 'user:id'));
|
||||
$tags->whereAdd('tagged = '.$this->id);
|
||||
$tags->whereAdd('tagger != '.$this->id);
|
||||
|
||||
$tags->limit(0, 1);
|
||||
$tags->fetch();
|
||||
|
||||
return ($tags->N == 0) ? false : true;
|
||||
}
|
||||
|
||||
function getTagSubscriptions($offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$lists = new Profile_list();
|
||||
$subs = new Profile_tag_subscription();
|
||||
|
||||
$lists->joinAdd($subs);
|
||||
#@fixme: postgres (round(date_part('epoch', my_date)))
|
||||
$lists->selectAdd('unix_timestamp(profile_tag_subscription.created) as "cursor"');
|
||||
|
||||
$lists->whereAdd('profile_tag_subscription.profile_id = '.$this->id);
|
||||
|
||||
if ($since_id>0) {
|
||||
$lists->whereAdd('cursor > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$lists->whereAdd('cursor <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$lists->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$lists->orderBy('"cursor" DESC');
|
||||
$lists->find();
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to join the given group.
|
||||
* May throw exceptions on failure.
|
||||
@ -358,6 +535,31 @@ class Profile extends Memcached_DataObject
|
||||
return new ArrayWrapper($profiles);
|
||||
}
|
||||
|
||||
function getTaggedSubscribers($tag)
|
||||
{
|
||||
$qry =
|
||||
'SELECT profile.* ' .
|
||||
'FROM profile JOIN (subscription, profile_tag, profile_list) ' .
|
||||
'ON profile.id = subscription.subscriber ' .
|
||||
'AND profile.id = profile_tag.tagged ' .
|
||||
'AND profile_tag.tagger = profile_list.tagger AND profile_tag.tag = profile_list.tag ' .
|
||||
'WHERE subscription.subscribed = %d ' .
|
||||
'AND subscription.subscribed != subscription.subscriber ' .
|
||||
'AND profile_tag.tagger = %d AND profile_tag.tag = "%s" ' .
|
||||
'AND profile_list.private = false ' .
|
||||
'ORDER BY subscription.created DESC';
|
||||
|
||||
$profile = new Profile();
|
||||
$tagged = array();
|
||||
|
||||
$cnt = $profile->query(sprintf($qry, $this->id, $this->id, $tag));
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$tagged[] = clone($profile);
|
||||
}
|
||||
return $tagged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending subscribers, who have not yet been approved.
|
||||
*
|
||||
|
926
classes/Profile_list.php
Normal file
926
classes/Profile_list.php
Normal file
@ -0,0 +1,926 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
*
|
||||
* 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 Notices
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Table Definition for profile_list
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Profile_list extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'profile_list'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $tagger; // int(4)
|
||||
public $tag; // varchar(64)
|
||||
public $description; // text
|
||||
public $private; // tinyint(1)
|
||||
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $mainpage; // varchar(255)
|
||||
public $tagged_count; // smallint
|
||||
public $subscriber_count; // smallint
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Profile_list',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
/**
|
||||
* return a profile_list record, given its tag and tagger.
|
||||
*
|
||||
* @param array $kv ideally array('tag' => $tag, 'tagger' => $tagger)
|
||||
*
|
||||
* @return Profile_list a Profile_list object with the given tag and tagger.
|
||||
*/
|
||||
|
||||
function pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Profile_list', $kv);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the tagger of this profile_list object
|
||||
*
|
||||
* @return Profile the tagger
|
||||
*/
|
||||
|
||||
function getTagger()
|
||||
{
|
||||
return Profile::staticGet('id', $this->tagger);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a string to identify this
|
||||
* profile_list in the user interface etc.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
|
||||
function getBestName()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a uri string for this profile_list
|
||||
*
|
||||
* @return String uri
|
||||
*/
|
||||
|
||||
function getUri()
|
||||
{
|
||||
$uri = null;
|
||||
if (Event::handle('StartProfiletagGetUri', array($this, &$uri))) {
|
||||
if (!empty($this->uri)) {
|
||||
$uri = $this->uri;
|
||||
} else {
|
||||
$uri = common_local_url('profiletagbyid',
|
||||
array('id' => $this->id, 'tagger_id' => $this->tagger));
|
||||
}
|
||||
}
|
||||
Event::handle('EndProfiletagGetUri', array($this, &$uri));
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a url to the homepage of this item
|
||||
*
|
||||
* @return String home url
|
||||
*/
|
||||
|
||||
function homeUrl()
|
||||
{
|
||||
$url = null;
|
||||
if (Event::handle('StartUserPeopletagHomeUrl', array($this, &$url))) {
|
||||
// normally stored in mainpage, but older ones may be null
|
||||
if (!empty($this->mainpage)) {
|
||||
$url = $this->mainpage;
|
||||
} else {
|
||||
$url = common_local_url('showprofiletag',
|
||||
array('tagger' => $this->getTagger()->nickname,
|
||||
'tag' => $this->tag));
|
||||
}
|
||||
}
|
||||
Event::handle('EndUserPeopletagHomeUrl', array($this, &$url));
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an immutable url for this object
|
||||
*
|
||||
* @return String permalink
|
||||
*/
|
||||
|
||||
function permalink()
|
||||
{
|
||||
$url = null;
|
||||
if (Event::handle('StartProfiletagPermalink', array($this, &$url))) {
|
||||
$url = common_local_url('profiletagbyid',
|
||||
array('id' => $this->id));
|
||||
}
|
||||
Event::handle('EndProfiletagPermalink', array($this, &$url));
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query notices by users associated with this tag,
|
||||
* but first check the cache before hitting the DB.
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since this id
|
||||
* @param integer $max_id=null maximum id in result
|
||||
*
|
||||
* @return Notice the query
|
||||
*/
|
||||
|
||||
function getNotices($offset, $limit, $since_id=null, $max_id=null)
|
||||
{
|
||||
$stream = new PeopletagNoticeStream($this);
|
||||
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query notices by users associated with this tag from the database.
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since this id
|
||||
* @param integer $max_id=null maximum id in result
|
||||
*
|
||||
* @return array array of notice ids.
|
||||
*/
|
||||
|
||||
function _streamDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$inbox = new Profile_tag_inbox();
|
||||
|
||||
$inbox->profile_tag_id = $this->id;
|
||||
|
||||
$inbox->selectAdd();
|
||||
$inbox->selectAdd('notice_id');
|
||||
|
||||
if ($since_id != 0) {
|
||||
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||
}
|
||||
|
||||
$inbox->orderBy('notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$inbox->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($inbox->find()) {
|
||||
while ($inbox->fetch()) {
|
||||
$ids[] = $inbox->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subscribers (local and remote) to this people tag
|
||||
* Order by reverse chronology
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since unix timestamp
|
||||
* @param integer $upto=null maximum unix timestamp when subscription was made
|
||||
*
|
||||
* @return Profile results
|
||||
*/
|
||||
|
||||
function getSubscribers($offset=0, $limit=null, $since=0, $upto=0)
|
||||
{
|
||||
$subs = new Profile();
|
||||
$sub = new Profile_tag_subscription();
|
||||
$sub->profile_tag_id = $this->id;
|
||||
|
||||
$subs->joinAdd($sub);
|
||||
$subs->selectAdd('unix_timestamp(profile_tag_subscription.' .
|
||||
'created) as "cursor"');
|
||||
|
||||
if ($since != 0) {
|
||||
$subs->whereAdd('cursor > ' . $since);
|
||||
}
|
||||
|
||||
if ($upto != 0) {
|
||||
$subs->whereAdd('cursor <= ' . $upto);
|
||||
}
|
||||
|
||||
if ($limit != null) {
|
||||
$subs->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$subs->orderBy('profile_tag_subscription.created DESC');
|
||||
$subs->find();
|
||||
|
||||
return $subs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all and only local subscribers to this people tag
|
||||
* used for distributing notices to user inboxes.
|
||||
*
|
||||
* @return array ids of users
|
||||
*/
|
||||
|
||||
function getUserSubscribers()
|
||||
{
|
||||
// XXX: cache this
|
||||
|
||||
$user = new User();
|
||||
if(common_config('db','quote_identifiers'))
|
||||
$user_table = '"user"';
|
||||
else $user_table = 'user';
|
||||
|
||||
$qry =
|
||||
'SELECT id ' .
|
||||
'FROM '. $user_table .' JOIN profile_tag_subscription '.
|
||||
'ON '. $user_table .'.id = profile_tag_subscription.profile_id ' .
|
||||
'WHERE profile_tag_subscription.profile_tag_id = %d ';
|
||||
|
||||
$user->query(sprintf($qry, $this->id));
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($user->fetch()) {
|
||||
$ids[] = $user->id;
|
||||
}
|
||||
|
||||
$user->free();
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a given profile has
|
||||
* subscribed to this people tag's timeline
|
||||
*
|
||||
* @param mixed $id User or Profile object or integer id
|
||||
*
|
||||
* @return boolean subscription status
|
||||
*/
|
||||
|
||||
function hasSubscriber($id)
|
||||
{
|
||||
if (!is_numeric($id)) {
|
||||
$id = $id->id;
|
||||
}
|
||||
|
||||
$sub = Profile_tag_subscription::pkeyGet(array('profile_tag_id' => $this->id,
|
||||
'profile_id' => $id));
|
||||
return !empty($sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profiles tagged with this people tag,
|
||||
* include modified timestamp as a "cursor" field
|
||||
* order by descending order of modified time
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since unix timestamp
|
||||
* @param integer $upto=null maximum unix timestamp when subscription was made
|
||||
*
|
||||
* @return Profile results
|
||||
*/
|
||||
|
||||
function getTagged($offset=0, $limit=null, $since=0, $upto=0)
|
||||
{
|
||||
$tagged = new Profile();
|
||||
$tagged->joinAdd(array('id', 'profile_tag:tagged'));
|
||||
|
||||
#@fixme: postgres
|
||||
$tagged->selectAdd('unix_timestamp(profile_tag.modified) as "cursor"');
|
||||
$tagged->whereAdd('profile_tag.tagger = '.$this->tagger);
|
||||
$tagged->whereAdd("profile_tag.tag = '{$this->tag}'");
|
||||
|
||||
if ($since != 0) {
|
||||
$tagged->whereAdd('cursor > ' . $since);
|
||||
}
|
||||
|
||||
if ($upto != 0) {
|
||||
$tagged->whereAdd('cursor <= ' . $upto);
|
||||
}
|
||||
|
||||
if ($limit != null) {
|
||||
$tagged->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$tagged->orderBy('profile_tag.modified DESC');
|
||||
$tagged->find();
|
||||
|
||||
return $tagged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gracefully delete one or many people tags
|
||||
* along with their members and subscriptions data
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function delete()
|
||||
{
|
||||
// force delete one item at a time.
|
||||
if (empty($this->id)) {
|
||||
$this->find();
|
||||
while ($this->fetch()) {
|
||||
$this->delete();
|
||||
}
|
||||
}
|
||||
|
||||
Profile_tag::cleanup($this);
|
||||
Profile_tag_subscription::cleanup($this);
|
||||
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a people tag gracefully
|
||||
* also change "tag" fields in profile_tag table
|
||||
*
|
||||
* @param Profile_list $orig Object's original form
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function update($orig=null)
|
||||
{
|
||||
$result = true;
|
||||
|
||||
if (!is_object($orig) && !$orig instanceof Profile_list) {
|
||||
parent::update($orig);
|
||||
}
|
||||
|
||||
// if original tag was different
|
||||
// check to see if the new tag already exists
|
||||
// if not, rename the tag correctly
|
||||
if($orig->tag != $this->tag || $orig->tagger != $this->tagger) {
|
||||
$existing = Profile_list::getByTaggerAndTag($this->tagger, $this->tag);
|
||||
if(!empty($existing)) {
|
||||
throw new ServerException(_('The tag you are trying to rename ' .
|
||||
'to already exists.'));
|
||||
}
|
||||
// move the tag
|
||||
// XXX: allow OStatus plugin to send out profile tag
|
||||
$result = Profile_tag::moveTag($orig, $this);
|
||||
}
|
||||
parent::update($orig);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an xml string representing this people tag
|
||||
* as the author of an atom feed
|
||||
*
|
||||
* @return string atom author element
|
||||
*/
|
||||
|
||||
function asAtomAuthor()
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
|
||||
$tagger = $this->getTagger();
|
||||
$xs->elementStart('author');
|
||||
$xs->element('name', null, '@' . $tagger->nickname . '/' . $this->tag);
|
||||
$xs->element('uri', null, $this->permalink());
|
||||
$xs->elementEnd('author');
|
||||
|
||||
return $xs->getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* return an xml string to represent this people tag
|
||||
* as the subject of an activitystreams feed.
|
||||
*
|
||||
* @return string activitystreams subject
|
||||
*/
|
||||
|
||||
function asActivitySubject()
|
||||
{
|
||||
return $this->asActivityNoun('subject');
|
||||
}
|
||||
|
||||
/**
|
||||
* return an xml string to represent this people tag
|
||||
* as a noun in an activitystreams feed.
|
||||
*
|
||||
* @param string $element the xml tag
|
||||
*
|
||||
* @return string activitystreams noun
|
||||
*/
|
||||
|
||||
function asActivityNoun($element)
|
||||
{
|
||||
$noun = ActivityObject::fromPeopletag($this);
|
||||
return $noun->asString('activity:' . $element);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cached number of profiles tagged with this
|
||||
* people tag, re-count if the argument is true.
|
||||
*
|
||||
* @param boolean $recount whether to ignore cache
|
||||
*
|
||||
* @return integer count
|
||||
*/
|
||||
|
||||
function taggedCount($recount=false)
|
||||
{
|
||||
if (!$recount) {
|
||||
return $this->tagged_count;
|
||||
}
|
||||
|
||||
$tags = new Profile_tag();
|
||||
$tags->tag = $this->tag;
|
||||
$tags->tagger = $this->tagger;
|
||||
$orig = clone($this);
|
||||
$this->tagged_count = (int) $tags->count('distinct tagged');
|
||||
$this->update($orig);
|
||||
|
||||
return $this->tagged_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cached number of profiles subscribed to this
|
||||
* people tag, re-count if the argument is true.
|
||||
*
|
||||
* @param boolean $recount whether to ignore cache
|
||||
*
|
||||
* @return integer count
|
||||
*/
|
||||
|
||||
function subscriberCount($recount=false)
|
||||
{
|
||||
if ($recount) {
|
||||
return $this->subscriber_count;
|
||||
}
|
||||
|
||||
$sub = new Profile_tag_subscription();
|
||||
$sub->profile_tag_id = $this->id;
|
||||
$orig = clone($this);
|
||||
$this->subscriber_count = (int) $sub->count('distinct profile_id');
|
||||
$this->update($orig);
|
||||
|
||||
return $this->subscriber_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Profile_list object by the
|
||||
* given tagger and with given tag
|
||||
*
|
||||
* @param integer $tagger the id of the creator profile
|
||||
* @param integer $tag the tag
|
||||
*
|
||||
* @return integer count
|
||||
*/
|
||||
|
||||
static function getByTaggerAndTag($tagger, $tag)
|
||||
{
|
||||
$ptag = Profile_list::pkeyGet(array('tagger' => $tagger, 'tag' => $tag));
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a profile_list record for a tag, tagger pair
|
||||
* if it doesn't exist, return it.
|
||||
*
|
||||
* @param integer $tagger the tagger
|
||||
* @param string $tag the tag
|
||||
* @param string $description description
|
||||
* @param boolean $private protected or not
|
||||
*
|
||||
* @return Profile_list the people tag object
|
||||
*/
|
||||
|
||||
static function ensureTag($tagger, $tag, $description=null, $private=false)
|
||||
{
|
||||
$ptag = Profile_list::getByTaggerAndTag($tagger, $tag);
|
||||
|
||||
if(empty($ptag->id)) {
|
||||
$args = array(
|
||||
'tag' => $tag,
|
||||
'tagger' => $tagger,
|
||||
'description' => $description,
|
||||
'private' => $private
|
||||
);
|
||||
|
||||
$new_tag = Profile_list::saveNew($args);
|
||||
|
||||
return $new_tag;
|
||||
}
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the maximum number of characters
|
||||
* that can be used in the description of
|
||||
* a people tag.
|
||||
*
|
||||
* determined by $config['peopletag']['desclimit']
|
||||
* if not set, falls back to $config['site']['textlimit']
|
||||
*
|
||||
* @return integer maximum number of characters
|
||||
*/
|
||||
|
||||
static function maxDescription()
|
||||
{
|
||||
$desclimit = common_config('peopletag', 'desclimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($desclimit)) {
|
||||
$desclimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $desclimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the length of given text exceeds
|
||||
* character limit.
|
||||
*
|
||||
* @param string $desc the description
|
||||
*
|
||||
* @return boolean is the descripition too long?
|
||||
*/
|
||||
|
||||
static function descriptionTooLong($desc)
|
||||
{
|
||||
$desclimit = self::maxDescription();
|
||||
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
|
||||
}
|
||||
|
||||
/**
|
||||
* save a new people tag, this should be always used
|
||||
* since it makes uri, homeurl, created and modified
|
||||
* timestamps and performs checks.
|
||||
*
|
||||
* @param array $fields an array with fields and their values
|
||||
*
|
||||
* @return mixed Profile_list on success, false on fail
|
||||
*/
|
||||
static function saveNew($fields) {
|
||||
|
||||
extract($fields);
|
||||
|
||||
$ptag = new Profile_list();
|
||||
|
||||
$ptag->query('BEGIN');
|
||||
|
||||
if (empty($tagger)) {
|
||||
throw new Exception(_('No tagger specified.'));
|
||||
}
|
||||
|
||||
if (empty($tag)) {
|
||||
throw new Exception(_('No tag specified.'));
|
||||
}
|
||||
|
||||
if (empty($mainpage)) {
|
||||
$mainpage = null;
|
||||
}
|
||||
|
||||
if (empty($uri)) {
|
||||
// fill in later...
|
||||
$uri = null;
|
||||
}
|
||||
|
||||
if (empty($mainpage)) {
|
||||
$mainpage = null;
|
||||
}
|
||||
|
||||
if (empty($description)) {
|
||||
$description = null;
|
||||
}
|
||||
|
||||
if (empty($private)) {
|
||||
$private = false;
|
||||
}
|
||||
|
||||
$ptag->tagger = $tagger;
|
||||
$ptag->tag = $tag;
|
||||
$ptag->description = $description;
|
||||
$ptag->private = $private;
|
||||
$ptag->uri = $uri;
|
||||
$ptag->mainpage = $mainpage;
|
||||
$ptag->created = common_sql_now();
|
||||
$ptag->modified = common_sql_now();
|
||||
|
||||
$result = $ptag->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($ptag, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Could not create profile tag.'));
|
||||
}
|
||||
|
||||
if (!isset($uri) || empty($uri)) {
|
||||
$orig = clone($ptag);
|
||||
$ptag->uri = common_local_url('profiletagbyid', array('id' => $ptag->id, 'tagger_id' => $ptag->tagger));
|
||||
$result = $ptag->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($ptag, 'UPDATE', __FILE__);
|
||||
throw new ServerException(_('Could not set profile tag URI.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($mainpage) || empty($mainpage)) {
|
||||
$orig = clone($ptag);
|
||||
$user = User::staticGet('id', $ptag->tagger);
|
||||
if(!empty($user)) {
|
||||
$ptag->mainpage = common_local_url('showprofiletag', array('tag' => $ptag->tag, 'tagger' => $user->nickname));
|
||||
} else {
|
||||
$ptag->mainpage = $uri; // assume this is a remote peopletag and the uri works
|
||||
}
|
||||
|
||||
$result = $ptag->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($ptag, 'UPDATE', __FILE__);
|
||||
throw new ServerException(_('Could not set profile tag mainpage.'));
|
||||
}
|
||||
}
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all items at given cursor position for api
|
||||
*
|
||||
* @param callback $fn a function that takes the following arguments in order:
|
||||
* $offset, $limit, $since_id, $max_id
|
||||
* and returns a Profile_list object after making the DB query
|
||||
* @param array $args arguments required for $fn
|
||||
* @param integer $cursor the cursor
|
||||
* @param integer $count max. number of results
|
||||
*
|
||||
* Algorithm:
|
||||
* - if cursor is 0, return empty list
|
||||
* - if cursor is -1, get first 21 items, next_cursor = 20th prev_cursor = 0
|
||||
* - if cursor is +ve get 22 consecutive items before starting at cursor
|
||||
* - return items[1..20] if items[0] == cursor else return items[0..21]
|
||||
* - prev_cursor = items[1]
|
||||
* - next_cursor = id of the last item being returned
|
||||
*
|
||||
* - if cursor is -ve get 22 consecutive items after cursor starting at cursor
|
||||
* - return items[1..20]
|
||||
*
|
||||
* @returns array (array (mixed items), int next_cursor, int previous_cursor)
|
||||
*/
|
||||
|
||||
// XXX: This should be in Memcached_DataObject... eventually.
|
||||
|
||||
static function getAtCursor($fn, $args, $cursor, $count=20)
|
||||
{
|
||||
$items = array();
|
||||
|
||||
$since_id = 0;
|
||||
$max_id = 0;
|
||||
$next_cursor = 0;
|
||||
$prev_cursor = 0;
|
||||
|
||||
if($cursor > 0) {
|
||||
// if cursor is +ve fetch $count+2 items before cursor starting at cursor
|
||||
$max_id = $cursor;
|
||||
$fn_args = array_merge($args, array(0, $count+2, 0, $max_id));
|
||||
$list = call_user_func_array($fn, $fn_args);
|
||||
while($list->fetch()) {
|
||||
$items[] = clone($list);
|
||||
}
|
||||
|
||||
if ((isset($items[0]->cursor) && $items[0]->cursor == $cursor) ||
|
||||
$items[0]->id == $cursor) {
|
||||
array_shift($items);
|
||||
$prev_cursor = isset($items[0]->cursor) ?
|
||||
-$items[0]->cursor : -$items[0]->id;
|
||||
} else {
|
||||
if (count($items) > $count+1) {
|
||||
array_shift($items);
|
||||
}
|
||||
// this means the cursor item has been deleted, check to see if there are more
|
||||
$fn_args = array_merge($args, array(0, 1, $cursor));
|
||||
$more = call_user_func($fn, $fn_args);
|
||||
if (!$more->fetch() || empty($more)) {
|
||||
// no more items.
|
||||
$prev_cursor = 0;
|
||||
} else {
|
||||
$prev_cursor = isset($items[0]->cursor) ?
|
||||
-$items[0]->cursor : -$items[0]->id;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($items)==$count+1) {
|
||||
// this means there is a next page.
|
||||
$next = array_pop($items);
|
||||
$next_cursor = isset($next->cursor) ?
|
||||
$items[$count-1]->cursor : $items[$count-1]->id;
|
||||
}
|
||||
|
||||
} else if($cursor < -1) {
|
||||
// if cursor is -ve fetch $count+2 items created after -$cursor-1
|
||||
$cursor = abs($cursor);
|
||||
$since_id = $cursor-1;
|
||||
|
||||
$fn_args = array_merge($args, array(0, $count+2, $since_id));
|
||||
$list = call_user_func_array($fn, $fn_args);
|
||||
while($list->fetch()) {
|
||||
$items[] = clone($list);
|
||||
}
|
||||
|
||||
$end = count($items)-1;
|
||||
if ((isset($items[$end]->cursor) && $items[$end]->cursor == $cursor) ||
|
||||
$items[$end]->id == $cursor) {
|
||||
array_pop($items);
|
||||
$next_cursor = isset($items[$end-1]->cursor) ?
|
||||
$items[$end-1]->cursor : $items[$end-1]->id;
|
||||
} else {
|
||||
$next_cursor = isset($items[$end]->cursor) ?
|
||||
$items[$end]->cursor : $items[$end]->id;
|
||||
if ($end > $count) array_pop($items); // excess item.
|
||||
|
||||
// check if there are more items for next page
|
||||
$fn_args = array_merge($args, array(0, 1, 0, $cursor));
|
||||
$more = call_user_func_array($fn, $fn_args);
|
||||
if (!$more->fetch() || empty($more)) {
|
||||
$next_cursor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($items) == $count+1) {
|
||||
// this means there is a previous page.
|
||||
$prev = array_shift($items);
|
||||
$prev_cursor = isset($prev->cursor) ?
|
||||
-$items[0]->cursor : -$items[0]->id;
|
||||
}
|
||||
} else if($cursor == -1) {
|
||||
$fn_args = array_merge($args, array(0, $count+1));
|
||||
$list = call_user_func_array($fn, $fn_args);
|
||||
|
||||
while($list->fetch()) {
|
||||
$items[] = clone($list);
|
||||
}
|
||||
|
||||
if (count($items)==$count+1) {
|
||||
$next = array_pop($items);
|
||||
if(isset($next->cursor)) {
|
||||
$next_cursor = $items[$count-1]->cursor;
|
||||
} else {
|
||||
$next_cursor = $items[$count-1]->id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return array($items, $next_cursor, $prev_cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* save a collection of people tags into the cache
|
||||
*
|
||||
* @param string $ckey cache key
|
||||
* @param Profile_list &$tag the results to store
|
||||
* @param integer $offset offset for slicing results
|
||||
* @param integer $limit maximum number of results
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
static function setCache($ckey, &$tag, $offset=0, $limit=null) {
|
||||
$cache = Cache::instance();
|
||||
if (empty($cache)) {
|
||||
return false;
|
||||
}
|
||||
$str = '';
|
||||
$tags = array();
|
||||
while ($tag->fetch()) {
|
||||
$str .= $tag->tagger . ':' . $tag->tag . ';';
|
||||
$tags[] = clone($tag);
|
||||
}
|
||||
$str = substr($str, 0, -1);
|
||||
if ($offset>=0 && !is_null($limit)) {
|
||||
$tags = array_slice($tags, $offset, $limit);
|
||||
}
|
||||
|
||||
$tag = new ArrayWrapper($tags);
|
||||
|
||||
return self::cacheSet($ckey, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* get people tags from the cache
|
||||
*
|
||||
* @param string $ckey cache key
|
||||
* @param integer $offset offset for slicing
|
||||
* @param integer $limit limit
|
||||
*
|
||||
* @return Profile_list results
|
||||
*/
|
||||
|
||||
static function getCached($ckey, $offset=0, $limit=null) {
|
||||
|
||||
$keys_str = self::cacheGet($ckey);
|
||||
if ($keys_str === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pairs = explode(';', $keys_str);
|
||||
$keys = array();
|
||||
foreach ($pairs as $pair) {
|
||||
$keys[] = explode(':', $pair);
|
||||
}
|
||||
|
||||
if ($offset>=0 && !is_null($limit)) {
|
||||
$keys = array_slice($keys, $offset, $limit);
|
||||
}
|
||||
return self::getByKeys($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* get Profile_list objects from the database
|
||||
* given their (tag, tagger) key pairs.
|
||||
*
|
||||
* @param array $keys array of array(tagger, tag)
|
||||
*
|
||||
* @return Profile_list results
|
||||
*/
|
||||
|
||||
static function getByKeys($keys) {
|
||||
$cache = Cache::instance();
|
||||
|
||||
if (!empty($cache)) {
|
||||
$tags = array();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$t = Profile_list::getByTaggerAndTag($key[0], $key[1]);
|
||||
if (!empty($t)) {
|
||||
$tags[] = $t;
|
||||
}
|
||||
}
|
||||
return new ArrayWrapper($tags);
|
||||
} else {
|
||||
$tag = new Profile_list();
|
||||
if (empty($keys)) {
|
||||
//if no IDs requested, just return the tag object
|
||||
return $tag;
|
||||
}
|
||||
|
||||
$pairs = array();
|
||||
foreach ($keys as $key) {
|
||||
$pairs[] = '(' . $key[0] . ', "' . $key[1] . '")';
|
||||
}
|
||||
|
||||
$tag->whereAdd('(tagger, tag) in (' . implode(', ', $pairs) . ')');
|
||||
|
||||
$tag->find();
|
||||
|
||||
$temp = array();
|
||||
|
||||
while ($tag->fetch()) {
|
||||
$temp[$tag->tagger.'-'.$tag->tag] = clone($tag);
|
||||
}
|
||||
|
||||
$wrapped = array();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$id = $key[0].'-'.$key[1];
|
||||
if (array_key_exists($id, $temp)) {
|
||||
$wrapped[] = $temp[$id];
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayWrapper($wrapped);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,31 +22,91 @@ class Profile_tag extends Memcached_DataObject
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function getTags($tagger, $tagged) {
|
||||
$tags = array();
|
||||
|
||||
// XXX: store this in memcached
|
||||
|
||||
$profile_tag = new Profile_tag();
|
||||
$profile_tag->tagger = $tagger;
|
||||
$profile_tag->tagged = $tagged;
|
||||
|
||||
$profile_tag->find();
|
||||
|
||||
while ($profile_tag->fetch()) {
|
||||
$tags[] = $profile_tag->tag;
|
||||
function pkeyGet($kv) {
|
||||
return Memcached_DataObject::pkeyGet('Profile_tag', $kv);
|
||||
}
|
||||
|
||||
$profile_tag->free();
|
||||
function links()
|
||||
{
|
||||
return array('tagger,tag' => 'profile_list:tagger,tag');
|
||||
}
|
||||
|
||||
function getMeta()
|
||||
{
|
||||
return Profile_list::pkeyGet(array('tagger' => $this->tagger, 'tag' => $this->tag));
|
||||
}
|
||||
|
||||
static function getTags($tagger, $tagged, $auth_user=null) {
|
||||
|
||||
$profile_list = new Profile_list();
|
||||
$include_priv = 1;
|
||||
|
||||
if (!($auth_user instanceof User ||
|
||||
$auth_user instanceof Profile) ||
|
||||
($auth_user->id !== $tagger)) {
|
||||
|
||||
$profile_list->private = false;
|
||||
$include_priv = 0;
|
||||
}
|
||||
|
||||
$key = sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $include_priv);
|
||||
$tags = Profile_list::getCached($key);
|
||||
if ($tags !== false) {
|
||||
return $tags;
|
||||
}
|
||||
|
||||
$profile_tag = new Profile_tag();
|
||||
$profile_list->tagger = $tagger;
|
||||
$profile_tag->tagged = $tagged;
|
||||
|
||||
$profile_list->selectAdd();
|
||||
|
||||
// only fetch id, tag, mainpage and
|
||||
// private hoping this will be faster
|
||||
$profile_list->selectAdd('profile_list.id, ' .
|
||||
'profile_list.tag, ' .
|
||||
'profile_list.mainpage, ' .
|
||||
'profile_list.private');
|
||||
$profile_list->joinAdd($profile_tag);
|
||||
$profile_list->find();
|
||||
|
||||
Profile_list::setCache($key, $profile_list);
|
||||
|
||||
return $profile_list;
|
||||
}
|
||||
|
||||
static function getTagsArray($tagger, $tagged, $auth_user_id=null)
|
||||
{
|
||||
$ptag = new Profile_tag();
|
||||
$ptag->tagger = $tagger;
|
||||
$ptag->tagged = $tagged;
|
||||
|
||||
if ($tagger != $auth_user_id) {
|
||||
$list = new Profile_list();
|
||||
$list->private = false;
|
||||
$ptag->joinAdd($list);
|
||||
$ptag->selectAdd();
|
||||
$ptag->selectAdd('profile_tag.tag');
|
||||
}
|
||||
|
||||
$tags = array();
|
||||
$ptag->find();
|
||||
while ($ptag->fetch()) {
|
||||
$tags[] = $ptag->tag;
|
||||
}
|
||||
$ptag->free();
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
static function setTags($tagger, $tagged, $newtags) {
|
||||
$newtags = array_unique($newtags);
|
||||
$oldtags = Profile_tag::getTags($tagger, $tagged);
|
||||
static function setTags($tagger, $tagged, $newtags, $privacy=array()) {
|
||||
|
||||
// Delete stuff that's old that not in new
|
||||
$newtags = array_unique($newtags);
|
||||
$oldtags = self::getTagsArray($tagger, $tagged, $tagger);
|
||||
|
||||
$ptag = new Profile_tag();
|
||||
|
||||
// Delete stuff that's in old and not in new
|
||||
|
||||
$to_delete = array_diff($oldtags, $newtags);
|
||||
|
||||
@ -54,33 +114,161 @@ class Profile_tag extends Memcached_DataObject
|
||||
|
||||
$to_insert = array_diff($newtags, $oldtags);
|
||||
|
||||
$profile_tag = new Profile_tag();
|
||||
|
||||
$profile_tag->tagger = $tagger;
|
||||
$profile_tag->tagged = $tagged;
|
||||
|
||||
$profile_tag->query('BEGIN');
|
||||
|
||||
foreach ($to_delete as $deltag) {
|
||||
$profile_tag->tag = $deltag;
|
||||
$result = $profile_tag->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($profile_tag, 'DELETE', __FILE__);
|
||||
return false;
|
||||
}
|
||||
self::unTag($tagger, $tagged, $deltag);
|
||||
}
|
||||
|
||||
foreach ($to_insert as $instag) {
|
||||
$profile_tag->tag = $instag;
|
||||
$result = $profile_tag->insert();
|
||||
$private = isset($privacy[$instag]) ? $privacy[$instag] : false;
|
||||
self::setTag($tagger, $tagged, $instag, null, $private);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
# set a single tag
|
||||
static function setTag($tagger, $tagged, $tag, $desc=null, $private=false) {
|
||||
|
||||
$ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
|
||||
'tagged' => $tagged,
|
||||
'tag' => $tag));
|
||||
|
||||
# if tag already exists, return it
|
||||
if(!empty($ptag)) {
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
$tagger_profile = Profile::staticGet('id', $tagger);
|
||||
$tagged_profile = Profile::staticGet('id', $tagged);
|
||||
|
||||
if (Event::handle('StartTagProfile', array($tagger_profile, $tagged_profile, $tag))) {
|
||||
|
||||
if (!$tagger_profile->canTag($tagged_profile)) {
|
||||
throw new ClientException(_('You cannot tag this user.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$tags = new Profile_list();
|
||||
$tags->tagger = $tagger;
|
||||
$count = (int) $tags->count('distinct tag');
|
||||
|
||||
if ($count >= common_config('peopletag', 'maxtags')) {
|
||||
throw new ClientException(sprintf(_('You already have created %d or more tags ' .
|
||||
'which is the maximum allowed number of tags. ' .
|
||||
'Try using or deleting some existing tags.'),
|
||||
common_config('peopletag', 'maxtags')));
|
||||
return false;
|
||||
}
|
||||
|
||||
$plist = new Profile_list();
|
||||
$plist->query('BEGIN');
|
||||
|
||||
$profile_list = Profile_list::ensureTag($tagger, $tag, $desc, $private);
|
||||
|
||||
if ($profile_list->taggedCount() >= common_config('peopletag', 'maxpeople')) {
|
||||
throw new ClientException(sprintf(_('You already have %d or more people tagged %s ' .
|
||||
'which is the maximum allowed number.' .
|
||||
'Try untagging others with the same tag first.'),
|
||||
common_config('peopletag', 'maxpeople'), $tag));
|
||||
return false;
|
||||
}
|
||||
|
||||
$newtag = new Profile_tag();
|
||||
|
||||
$newtag->tagger = $tagger;
|
||||
$newtag->tagged = $tagged;
|
||||
$newtag->tag = $tag;
|
||||
|
||||
$result = $newtag->insert();
|
||||
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($profile_tag, 'INSERT', __FILE__);
|
||||
common_log_db_error($newtag, 'INSERT', __FILE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$plist->query('COMMIT');
|
||||
Event::handle('EndTagProfile', array($newtag));
|
||||
} catch (Exception $e) {
|
||||
$newtag->delete();
|
||||
$profile_list->delete();
|
||||
throw $e;
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile_list->taggedCount(true);
|
||||
self::blowCaches($tagger, $tagged);
|
||||
}
|
||||
|
||||
return $newtag;
|
||||
}
|
||||
|
||||
static function unTag($tagger, $tagged, $tag) {
|
||||
$ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
|
||||
'tagged' => $tagged,
|
||||
'tag' => $tag));
|
||||
if (!$ptag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Event::handle('StartUntagProfile', array($ptag))) {
|
||||
$orig = clone($ptag);
|
||||
$result = $ptag->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($this, 'DELETE', __FILE__);
|
||||
return false;
|
||||
}
|
||||
Event::handle('EndUntagProfile', array($orig));
|
||||
if ($result) {
|
||||
$profile_list = Profile_list::pkeyGet(array('tag' => $tag, 'tagger' => $tagger));
|
||||
$profile_list->taggedCount(true);
|
||||
self::blowCaches($tagger, $tagged);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$profile_tag->query('COMMIT');
|
||||
// @fixme: move this to Profile_list?
|
||||
static function cleanup($profile_list) {
|
||||
$ptag = new Profile_tag();
|
||||
$ptag->tagger = $profile_list->tagger;
|
||||
$ptag->tag = $profile_list->tag;
|
||||
$ptag->find();
|
||||
|
||||
while($ptag->fetch()) {
|
||||
if (Event::handle('StartUntagProfile', array($ptag))) {
|
||||
$orig = clone($ptag);
|
||||
$result = $ptag->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($this, 'DELETE', __FILE__);
|
||||
}
|
||||
Event::handle('EndUntagProfile', array($orig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move a tag!
|
||||
static function moveTag($orig, $new) {
|
||||
$tags = new Profile_tag();
|
||||
$qry = 'UPDATE profile_tag SET ' .
|
||||
'tag = "%s", tagger = "%s" ' .
|
||||
'WHERE tag = "%s" ' .
|
||||
'AND tagger = "%s"';
|
||||
$result = $tags->query(sprintf($qry, $new->tag, $new->tagger,
|
||||
$orig->tag, $orig->tagger));
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($tags, 'UPDATE', __FILE__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static function blowCaches($tagger, $tagged) {
|
||||
foreach (array(0, 1) as $perm) {
|
||||
self::blow(sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $perm));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -96,6 +284,6 @@ class Profile_tag extends Memcached_DataObject
|
||||
while ($profile->fetch()) {
|
||||
$tagged[] = clone($profile);
|
||||
}
|
||||
return $tagged;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
27
classes/Profile_tag_inbox.php
Normal file
27
classes/Profile_tag_inbox.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for profile_tag_inbox
|
||||
*/
|
||||
|
||||
class Profile_tag_inbox extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'profile_tag_inbox'; // table name
|
||||
public $profile_tag_id; // int(4) primary_key not_null
|
||||
public $notice_id; // int(4) primary_key not_null
|
||||
public $created; // datetime() not_null
|
||||
|
||||
/* Static get */
|
||||
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Profile_tag_inbox',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
function pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Profile_tag_inbox', $kv);
|
||||
}
|
||||
}
|
103
classes/Profile_tag_subscription.php
Normal file
103
classes/Profile_tag_subscription.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for profile_tag_subscription
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Profile_tag_subscription extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'profile_tag_subscription'; // table name
|
||||
public $profile_tag_id; // int(4) not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('Profile_tag_subscription',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
function pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Profile_tag_subscription', $kv);
|
||||
}
|
||||
|
||||
static function add($peopletag, $profile)
|
||||
{
|
||||
if ($peopletag->private) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Event::handle('StartSubscribePeopletag', array($peopletag, $profile))) {
|
||||
$args = array('profile_tag_id' => $peopletag->id,
|
||||
'profile_id' => $profile->id);
|
||||
$existing = Profile_tag_subscription::pkeyGet($args);
|
||||
if(!empty($existing)) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
$sub = new Profile_tag_subscription();
|
||||
$sub->profile_tag_id = $peopletag->id;
|
||||
$sub->profile_id = $profile->id;
|
||||
$sub->created = common_sql_now();
|
||||
|
||||
$result = $sub->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($sub, 'INSERT', __FILE__);
|
||||
throw new Exception(_("Adding people tag subscription failed."));
|
||||
}
|
||||
|
||||
$ptag = Profile_list::staticGet('id', $peopletag->id);
|
||||
$ptag->subscriberCount(true);
|
||||
|
||||
Event::handle('EndSubscribePeopletag', array($peopletag, $profile));
|
||||
return $ptag;
|
||||
}
|
||||
}
|
||||
|
||||
static function remove($peopletag, $profile)
|
||||
{
|
||||
$sub = Profile_tag_subscription::pkeyGet(array('profile_tag_id' => $peopletag->id,
|
||||
'profile_id' => $profile->id));
|
||||
|
||||
if (empty($sub)) {
|
||||
// silence is golden?
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Event::handle('StartUnsubscribePeopletag', array($peopletag, $profile))) {
|
||||
$result = $sub->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($sub, 'DELETE', __FILE__);
|
||||
throw new Exception(_("Removing people tag subscription failed."));
|
||||
}
|
||||
|
||||
$peopletag->subscriberCount(true);
|
||||
|
||||
Event::handle('EndUnsubscribePeopletag', array($peopletag, $profile));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// called if a tag gets deleted / made private
|
||||
static function cleanup($profile_list) {
|
||||
$subs = new self();
|
||||
$subs->profile_tag_id = $profile_list->id;
|
||||
$subs->find();
|
||||
|
||||
while($subs->fetch()) {
|
||||
$profile = Profile::staticGet('id', $subs->profile_id);
|
||||
Event::handle('StartUnsubscribePeopletag', array($profile_list, $profile));
|
||||
// Delete anyway
|
||||
$subs->delete();
|
||||
Event::handle('StartUnsubscribePeopletag', array($profile_list, $profile));
|
||||
}
|
||||
}
|
||||
}
|
@ -532,12 +532,12 @@ class User extends Memcached_DataObject
|
||||
|
||||
function getSelfTags()
|
||||
{
|
||||
return Profile_tag::getTags($this->id, $this->id);
|
||||
return Profile_tag::getTagsArray($this->id, $this->id, $this->id);
|
||||
}
|
||||
|
||||
function setSelfTags($newtags)
|
||||
function setSelfTags($newtags, $privacy)
|
||||
{
|
||||
return Profile_tag::setTags($this->id, $this->id, $newtags);
|
||||
return Profile_tag::setTags($this->id, $this->id, $newtags, $privacy);
|
||||
}
|
||||
|
||||
function block($other)
|
||||
|
@ -462,6 +462,43 @@ tagger = K
|
||||
tagged = K
|
||||
tag = K
|
||||
|
||||
[profile_list]
|
||||
id = 129
|
||||
tagger = 129
|
||||
tag = 130
|
||||
description = 34
|
||||
private = 17
|
||||
created = 142
|
||||
modified = 384
|
||||
uri = 130
|
||||
mainpage = 130
|
||||
tagged_count = 129
|
||||
subscriber_count = 129
|
||||
|
||||
[profile_list__keys]
|
||||
id = U
|
||||
tagger = K
|
||||
tag = K
|
||||
|
||||
[profile_tag_inbox]
|
||||
profile_tag_id = 129
|
||||
notice_id = 129
|
||||
created = 142
|
||||
|
||||
[profile_tag_inbox__keys]
|
||||
profile_tag_id = K
|
||||
notice_id = K
|
||||
|
||||
[profile_tag_subscription]
|
||||
profile_tag_id = 129
|
||||
profile_id = 129
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[profile_tag_subscription__keys]
|
||||
profile_tag_id = K
|
||||
profile_id = K
|
||||
|
||||
[queue_item]
|
||||
id = 129
|
||||
frame = 194
|
||||
|
@ -55,3 +55,23 @@ file_id = file:id
|
||||
file_id = file:id
|
||||
post_id = notice:id
|
||||
|
||||
[profile_list]
|
||||
tagger = profile:id
|
||||
|
||||
[profile_tag]
|
||||
tagger = profile:id
|
||||
tagged = profile:id
|
||||
; in class definition:
|
||||
;tag,tagger = profile_list:tag,tagger
|
||||
|
||||
[profile_list]
|
||||
tagger = profile:id
|
||||
|
||||
[profile_tag_inbox]
|
||||
profile_tag_id = profile_list:id
|
||||
notice_id = notice:id
|
||||
|
||||
[profile_tag_subscription]
|
||||
profile_tag_id = profile_list:id
|
||||
profile_id = profile:id
|
||||
|
||||
|
@ -182,6 +182,29 @@ $config['sphinx']['port'] = 3312;
|
||||
// $config['memcached']['server'] = 'localhost';
|
||||
// $config['memcached']['port'] = 11211;
|
||||
|
||||
// People tags
|
||||
// Maximum number of tags a user can create:
|
||||
// $config['peopletag']['maxtags'] = 100;
|
||||
// Maximum number of people can have the same tag by the same user
|
||||
// $config['peopletag']['maxpeople'] = 500;
|
||||
// Types of users one can tag.
|
||||
// Everyone.
|
||||
// $config['peopletag']['allow_tagging']['all'] = true;
|
||||
// Local only.
|
||||
// $config['peopletag']['allow_tagging']['local'] = true;
|
||||
// Subscriptions / Subscribers only (including remote)
|
||||
// $config['peopletag']['allow_tagging']['subs'] = true;
|
||||
// Remote.
|
||||
// $config['peopletag']['allow_tagging']['remote'] = true;
|
||||
// Examples:
|
||||
// The following set of options allows tagging local users and
|
||||
// remote subscribers / subscription.
|
||||
// $config['peopletag']['allow_tagging']['all'] = false;
|
||||
// $config['peopletag']['allow_tagging']['local'] = true;
|
||||
// $config['peopletag']['allow_tagging']['subs'] = true;
|
||||
// Or:
|
||||
// $config['peopletag']['allow_tagging'] = array('local' => true, 'subs' =>true);
|
||||
|
||||
// Disable post-by-email
|
||||
// $config['emailpost']['enabled'] = false;
|
||||
|
||||
|
4
db/095topeopletags.sql
Normal file
4
db/095topeopletags.sql
Normal file
@ -0,0 +1,4 @@
|
||||
/* populate people tags metadata */
|
||||
|
||||
insert into profile_list (tagger, tag, modified, description, private)
|
||||
select distinct tagger, tag, modified, null, false from profile_tag;
|
73
db/core.php
73
db/core.php
@ -610,8 +610,9 @@ $schema['profile_tag'] = array(
|
||||
),
|
||||
'primary key' => array('tagger', 'tagged', 'tag'),
|
||||
'foreign keys' => array(
|
||||
'profile_tag_tagger_fkey' => array('user', array('tagger' => 'id')),
|
||||
'profile_tag_tagger_fkey' => array('profile', array('tagger' => 'id')),
|
||||
'profile_tag_tagged_fkey' => array('profile', array('tagged' => 'id')),
|
||||
'profile_tag_tag_fkey' => array('profile_list', array('tag' => 'tag')),
|
||||
),
|
||||
'indexes' => array(
|
||||
'profile_tag_modified_idx' => array('modified'),
|
||||
@ -620,6 +621,76 @@ $schema['profile_tag'] = array(
|
||||
),
|
||||
);
|
||||
|
||||
$schema['profile_list'] = array(
|
||||
'fields' => array(
|
||||
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
|
||||
'tagger' => array('type' => 'int', 'not null' => true, 'description' => 'user making the tag'),
|
||||
'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'people tag'),
|
||||
'description' => array('type' => 'text', 'description' => 'description of the people tag'),
|
||||
'private' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'is this tag private'),
|
||||
|
||||
'created' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was added'),
|
||||
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was modified'),
|
||||
|
||||
'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
|
||||
'mainpage' => array('type' => 'varchar', 'length' => 255, 'description' => 'page to link to'),
|
||||
'tagged_count' => array('type' => 'int', 'default' => 0, 'description' => 'number of people tagged with this tag by this user'),
|
||||
'subscriber_count' => array('type' => 'int', 'default' => 0, 'description' => 'number of subscribers to this tag'),
|
||||
),
|
||||
'primary key' => array('tagger', 'tag'),
|
||||
'unique keys' => array(
|
||||
'profile_list_id_key' => array('id')
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'profile_list_tagger_fkey' => array('profile', array('tagger' => 'id')),
|
||||
),
|
||||
'indexes' => array(
|
||||
'profile_list_modified_idx' => array('modified'),
|
||||
'profile_list_tag_idx' => array('tag'),
|
||||
'profile_list_tagger_tag_idx' => array('tagger', 'tag'),
|
||||
'profile_list_tagged_count_idx' => array('tagged_count'),
|
||||
'profile_list_subscriber_count_idx' => array('subscriber_count'),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['profile_tag_inbox'] = array(
|
||||
'description' => 'Many-many table listing notices associated with people tags.',
|
||||
'fields' => array(
|
||||
'profile_tag_id' => array('type' => 'int', 'not null' => true, 'description' => 'people tag receiving the message'),
|
||||
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice received'),
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice was created'),
|
||||
),
|
||||
'primary key' => array('profile_tag_id', 'notice_id'),
|
||||
'foreign keys' => array(
|
||||
'profile_tag_inbox_profile_list_id_fkey' => array('profile_list', array('profile_tag_id' => 'id')),
|
||||
'profile_tag_inbox_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
|
||||
),
|
||||
'indexes' => array(
|
||||
'profile_tag_inbox_created_idx' => array('created'),
|
||||
'profile_tag_inbox_profile_tag_id_idx' => array('profile_tag_id'),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['profile_tag_subscription'] = array(
|
||||
'fields' => array(
|
||||
'profile_tag_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile_tag'),
|
||||
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
|
||||
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
|
||||
),
|
||||
'primary key' => array('profile_tag_id', 'profile_id'),
|
||||
'foreign keys' => array(
|
||||
'profile_tag_subscription_profile_list_id_fkey' => array('profile_list', array('profile_tag_id' => 'id')),
|
||||
'profile_tag_subscription_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
|
||||
),
|
||||
'indexes' => array(
|
||||
// @fixme probably we want a (profile_id, created) index here?
|
||||
'profile_tag_subscription_profile_id_idx' => array('profile_id'),
|
||||
'profile_tag_subscription_created_idx' => array('created'),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['profile_block'] = array(
|
||||
'fields' => array(
|
||||
'blocker' => array('type' => 'int', 'not null' => true, 'description' => 'user making the block'),
|
||||
|
@ -403,7 +403,7 @@ create table notice_inbox (
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table profile_tag (
|
||||
tagger integer not null comment 'user making the tag' references user (id),
|
||||
tagger integer not null comment 'user making the tag' references profile (id),
|
||||
tagged integer not null comment 'profile tagged' references profile (id),
|
||||
tag varchar(64) not null comment 'hash tag associated with this notice',
|
||||
modified timestamp comment 'date the tag was added',
|
||||
@ -414,6 +414,53 @@ create table profile_tag (
|
||||
index profile_tag_tagged_idx (tagged)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
/* people tag metadata */
|
||||
create table profile_list (
|
||||
id integer auto_increment unique key comment 'unique identifier',
|
||||
tagger integer not null comment 'user making the tag' references profile (id),
|
||||
tag varchar(64) not null comment 'hash tag',
|
||||
description text comment 'description for the tag',
|
||||
private tinyint(1) default 0 comment 'is this list private',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
uri varchar(255) unique key comment 'universal identifier',
|
||||
mainpage varchar(255) comment 'page for tag info info to link to',
|
||||
tagged_count smallint not null default 0 comment 'number of people tagged',
|
||||
subscriber_count smallint not null default 0 comment 'number of people subscribing',
|
||||
|
||||
constraint primary key (tagger, tag),
|
||||
index profile_list_tag_idx (tag),
|
||||
index profile_list_tagged_count_idx (tagged_count),
|
||||
index profile_list_modified_idx (modified),
|
||||
index profile_list_subscriber_count_idx (subscriber_count)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table profile_tag_inbox (
|
||||
profile_tag_id integer not null comment 'peopletag receiving the message' references profile_tag (id),
|
||||
notice_id integer not null comment 'notice received' references notice (id),
|
||||
created datetime not null comment 'date the notice was created',
|
||||
|
||||
constraint primary key (profile_tag_id, notice_id),
|
||||
index profile_tag_inbox_created_idx (created),
|
||||
index profile_tag_inbox_notice_id_idx (notice_id)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table profile_tag_subscription (
|
||||
profile_tag_id integer not null comment 'foreign key to profile_tag' references profile_list (id),
|
||||
|
||||
profile_id integer not null comment 'foreign key to profile table' references profile (id),
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
constraint primary key (profile_tag_id, profile_id),
|
||||
index profile_tag_subscription_profile_id_idx (profile_id),
|
||||
index profile_tag_subscription_created_idx (created)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table profile_block (
|
||||
blocker integer not null comment 'user making the block' references user (id),
|
||||
blocked integer not null comment 'profile that is blocked' references profile (id),
|
||||
|
49
doc-src/tags
49
doc-src/tags
@ -25,20 +25,49 @@ Tagging yourself
|
||||
----------------
|
||||
|
||||
You can also add tags for yourself on your [profile
|
||||
settings](%%action.profilesettings%%) page. Use single words to
|
||||
settings](%%action.profilesettings%%) page or by using the edit tags
|
||||
button on your profile page. Use single words to
|
||||
describe yourself, your experiences and your interest. The tags will
|
||||
become links on your profile page to a list of all the users on the
|
||||
site who use that same tag. It can be a nice way to find people who
|
||||
are related to you geographically or who have a common interest.
|
||||
|
||||
Tagging your subscriptions
|
||||
--------------------------
|
||||
Tagging others
|
||||
--------------
|
||||
|
||||
You can also tag your subscriptions, on the subscriptions page. This
|
||||
makes it easy to organize your subscriptions into groups and sort
|
||||
through them separately.
|
||||
You can also tag other users by using the edit tags button next to
|
||||
their profile. Such tags are called *people tags*. Once you have
|
||||
created a people tag, you can add or remove users from it using the
|
||||
tag's edit form. This makes it easy to organize your subscriptions
|
||||
into groups and sort through them separately. Also, it will let
|
||||
you create custom lists of people that others can subscribe to.
|
||||
|
||||
You can also send a notice "to the attention of" your subscribers
|
||||
whom you've marked with a particular tag (note: *not* people who've
|
||||
marked themselves with that tag). "@#family hello" will send a
|
||||
notice to all your subscribers you've marked with the tag 'family'.
|
||||
|
||||
Private and public people tags
|
||||
------------------------------
|
||||
|
||||
A private people tag is only visible to the creator, it cannot be
|
||||
subscribed to, but the timeline can be viewed. To create a new
|
||||
private prepend a '.' to the tag in the tags editing box. To set
|
||||
an existing public tag as private or vice-versa, go to the tag's
|
||||
edit page.
|
||||
|
||||
The most used public tags are displayed in the
|
||||
[public people tag cloud](%%action.publicpeopletagcloud%%). Their
|
||||
size shows their frequency of use.
|
||||
|
||||
Remote people tags
|
||||
------------------
|
||||
|
||||
You can even [tag remote users](%%action.profilesettings%%). Just
|
||||
enter the remote profile's URI and click on the "Fetch" button to
|
||||
fetch the profile, you can then add tags and save them.
|
||||
|
||||
Subscribing to the timeline of a people tag on another server also
|
||||
works. Just copy the URL of the people tag's timeline page to the
|
||||
[OStatus subscription](%%action.ostatussub%%) form.
|
||||
|
||||
You can also send a notice "to the attention of" everyone you've
|
||||
marked with a particular tag (note: *not* people who've marked
|
||||
themselves with that tag). "@#family hello" will send a notice to
|
||||
everyone you've marked with the tag 'family'.
|
187
js/util.js
187
js/util.js
@ -476,6 +476,74 @@ var SN = { // StatusNet
|
||||
});
|
||||
},
|
||||
|
||||
FormProfileSearchXHR: function(form) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'xml',
|
||||
url: form.attr('action'),
|
||||
data: form.serialize() + '&ajax=1',
|
||||
beforeSend: function(xhr) {
|
||||
form
|
||||
.addClass(SN.C.S.Processing)
|
||||
.find('.submit')
|
||||
.addClass(SN.C.S.Disabled)
|
||||
.attr(SN.C.S.Disabled, SN.C.S.Disabled);
|
||||
},
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
alert(errorThrown || textStatus);
|
||||
},
|
||||
success: function(data, textStatus) {
|
||||
var results_placeholder = $('#profile_search_results');
|
||||
if (typeof($('ul', data)[0]) != 'undefined') {
|
||||
var list = document._importNode($('ul', data)[0], true);
|
||||
results_placeholder.replaceWith(list);
|
||||
}
|
||||
else {
|
||||
var _error = $('<li/>').append(document._importNode($('p', data)[0], true));
|
||||
results_placeholder.html(_error);
|
||||
}
|
||||
form
|
||||
.removeClass(SN.C.S.Processing)
|
||||
.find('.submit')
|
||||
.removeClass(SN.C.S.Disabled)
|
||||
.attr(SN.C.S.Disabled, false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
FormPeopletagsXHR: function(form) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'xml',
|
||||
url: form.attr('action'),
|
||||
data: form.serialize() + '&ajax=1',
|
||||
beforeSend: function(xhr) {
|
||||
form.find('.submit')
|
||||
.addClass(SN.C.S.Processing)
|
||||
.addClass(SN.C.S.Disabled)
|
||||
.attr(SN.C.S.Disabled, SN.C.S.Disabled);
|
||||
},
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
alert(errorThrown || textStatus);
|
||||
},
|
||||
success: function(data, textStatus) {
|
||||
var results_placeholder = form.parents('.entity_tags');
|
||||
if (typeof($('.entity_tags', data)[0]) != 'undefined') {
|
||||
var tags = document._importNode($('.entity_tags', data)[0], true);
|
||||
$(tags).find('.editable').append($('<button class="peopletags_edit_button"/>'));
|
||||
results_placeholder.replaceWith(tags);
|
||||
} else {
|
||||
results_placeholder.find('p').remove();
|
||||
results_placeholder.append(document._importNode($('p', data)[0], true));
|
||||
form.removeClass(SN.C.S.Processing)
|
||||
.find('.submit')
|
||||
.removeClass(SN.C.S.Disabled)
|
||||
.attr(SN.C.S.Disabled, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
normalizeGeoData: function(form) {
|
||||
SN.C.I.NoticeDataGeo.NLat = form.find('[name=lat]').val();
|
||||
SN.C.I.NoticeDataGeo.NLon = form.find('[name=lon]').val();
|
||||
@ -505,6 +573,7 @@ var SN = { // StatusNet
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch an XML DOM from an XHR's response data.
|
||||
*
|
||||
@ -1430,10 +1499,28 @@ var SN = { // StatusNet
|
||||
*/
|
||||
EntityActions: function() {
|
||||
if ($('body.user_in').length > 0) {
|
||||
$('.form_user_subscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_user_unsubscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_group_join').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_group_leave').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_user_nudge').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_peopletag_subscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_peopletag_unsubscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_user_add_peopletag').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
$('.form_user_remove_peopletag').live('click', function() { SN.U.FormXHR($(this)); return false; });
|
||||
|
||||
SN.U.NewDirectMessage();
|
||||
}
|
||||
},
|
||||
|
||||
ProfileSearch: function() {
|
||||
if ($('body.user_in').length > 0) {
|
||||
$('.form_peopletag_edit_user_search input.submit').live('click', function() {
|
||||
SN.U.FormProfileSearchXHR($(this).parents('form')); return false;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Run setup code for login form:
|
||||
*
|
||||
@ -1456,6 +1543,100 @@ var SN = { // StatusNet
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a people tag edit box is shown in the interface
|
||||
*
|
||||
* - loads the jQuery UI autocomplete plugin
|
||||
* - sets event handlers for tag completion
|
||||
*
|
||||
*/
|
||||
PeopletagAutocomplete: function(txtBox) {
|
||||
var split = function(val) {
|
||||
return val.split( /\s+/ );
|
||||
}
|
||||
var extractLast = function(term) {
|
||||
return split(term).pop();
|
||||
}
|
||||
|
||||
// don't navigate away from the field on tab when selecting an item
|
||||
txtBox.live( "keydown", function( event ) {
|
||||
if ( event.keyCode === $.ui.keyCode.TAB &&
|
||||
$(this).data( "autocomplete" ).menu.active ) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}).autocomplete({
|
||||
minLength: 0,
|
||||
source: function(request, response) {
|
||||
// delegate back to autocomplete, but extract the last term
|
||||
response($.ui.autocomplete.filter(
|
||||
SN.C.PtagACData, extractLast(request.term)));
|
||||
},
|
||||
focus: function() {
|
||||
return false;
|
||||
},
|
||||
select: function(event, ui) {
|
||||
var terms = split(this.value);
|
||||
terms.pop();
|
||||
terms.push(ui.item.value);
|
||||
terms.push("");
|
||||
this.value = terms.join(" ");
|
||||
return false;
|
||||
}
|
||||
}).data('autocomplete')._renderItem = function(ul, item) {
|
||||
// FIXME: with jQuery UI you cannot have it highlight the match
|
||||
var _l = '<a class="ptag-ac-line-tag">' + item.tag
|
||||
+ ' <em class="privacy_mode">' + item.mode + '</em>'
|
||||
+ '<span class="freq">' + item.freq + '</span></a>'
|
||||
|
||||
return $("<li/>")
|
||||
.addClass('mode-' + item.mode)
|
||||
.addClass('ptag-ac-line')
|
||||
.data("item.autocomplete", item)
|
||||
.append(_l)
|
||||
.appendTo(ul);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Run setup for the ajax people tags editor
|
||||
*
|
||||
* - show edit button
|
||||
* - set event handle for click on edit button
|
||||
* - loads people tag autocompletion data if not already present
|
||||
* or if it is stale.
|
||||
*
|
||||
*/
|
||||
PeopleTags: function() {
|
||||
$('.user_profile_tags .editable').append($('<button class="peopletags_edit_button"/>'));
|
||||
|
||||
$('.peopletags_edit_button').live('click', function() {
|
||||
var form = $(this).parents('dd').eq(0).find('form');
|
||||
// We can buy time from the above animation
|
||||
|
||||
$.ajax({
|
||||
url: _peopletagAC,
|
||||
dataType: 'json',
|
||||
data: {token: $('#token').val()},
|
||||
ifModified: true,
|
||||
success: function(data) {
|
||||
// item.label is used to match
|
||||
for (i=0; i < data.length; i++) {
|
||||
data[i].label = data[i].tag;
|
||||
}
|
||||
|
||||
SN.C.PtagACData = data;
|
||||
SN.Init.PeopletagAutocomplete(form.find('#tags'));
|
||||
}
|
||||
});
|
||||
|
||||
$(this).parents('ul').eq(0).fadeOut(200, function() {form.fadeIn(200).find('input#tags')});
|
||||
});
|
||||
|
||||
$('.user_profile_tags form .submit').live('click', function() {
|
||||
SN.U.FormPeopletagsXHR($(this).parents('form')); return false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up any generic 'ajax' form so it submits via AJAX with auto-replacement.
|
||||
*/
|
||||
@ -1548,5 +1729,11 @@ $(document).ready(function(){
|
||||
if ($('#form_login').length > 0) {
|
||||
SN.Init.Login();
|
||||
}
|
||||
if ($('#profile_search_results').length > 0) {
|
||||
SN.Init.ProfileSearch();
|
||||
}
|
||||
if ($('.user_profile_tags .editable').length > 0) {
|
||||
SN.Init.PeopleTags();
|
||||
}
|
||||
});
|
||||
|
||||
|
2
js/util.min.js
vendored
2
js/util.min.js
vendored
File diff suppressed because one or more lines are too long
@ -34,6 +34,8 @@ if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/peopletags.php';
|
||||
|
||||
/**
|
||||
* Profile block to show for an account
|
||||
*
|
||||
@ -92,6 +94,22 @@ class AccountProfileBlock extends ProfileBlock
|
||||
return $this->profile->bio;
|
||||
}
|
||||
|
||||
function showTags()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
$self_tags = new SelftagsWidget($this->out, $this->profile, $this->profile);
|
||||
$self_tags->show();
|
||||
|
||||
if ($cur) {
|
||||
// don't show self-tags again
|
||||
if ($cur->id != $this->profile->id && $cur->getProfile()->canTag($this->profile)) {
|
||||
$tags = new PeopletagsWidget($this->out, $cur, $this->profile);
|
||||
$tags->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showActions()
|
||||
{
|
||||
if (Event::handle('StartProfilePageActionsSection', array($this->out, $this->profile))) {
|
||||
|
@ -317,6 +317,7 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.js').'"); }');
|
||||
$this->script('jquery.joverlay.js');
|
||||
}
|
||||
|
||||
Event::handle('EndShowJQueryScripts', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
||||
@ -327,7 +328,10 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->script('util.js');
|
||||
$this->script('xbImportNode.js');
|
||||
$this->script('geometa.js');
|
||||
|
||||
}
|
||||
$this->inlineScript('var _peopletagAC = "' .
|
||||
common_local_url('peopletagautocomplete') . '";');
|
||||
$this->showScriptMessages();
|
||||
// Frame-busting code to avoid clickjacking attacks.
|
||||
$this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||
|
@ -64,6 +64,7 @@ class ActivityObject
|
||||
const BOOKMARK = 'http://activitystrea.ms/schema/1.0/bookmark';
|
||||
const PERSON = 'http://activitystrea.ms/schema/1.0/person';
|
||||
const GROUP = 'http://activitystrea.ms/schema/1.0/group';
|
||||
const _LIST = 'http://activitystrea.ms/schema/1.0/list'; // LIST is reserved
|
||||
const PLACE = 'http://activitystrea.ms/schema/1.0/place';
|
||||
const COMMENT = 'http://activitystrea.ms/schema/1.0/comment';
|
||||
// ^^^^^^^^^^ tea!
|
||||
@ -92,6 +93,7 @@ class ActivityObject
|
||||
public $title;
|
||||
public $summary;
|
||||
public $content;
|
||||
public $owner;
|
||||
public $link;
|
||||
public $source;
|
||||
public $avatarLinks = array();
|
||||
@ -168,6 +170,10 @@ class ActivityObject
|
||||
Activity::MEDIA
|
||||
);
|
||||
}
|
||||
if ($this->type == self::_LIST) {
|
||||
$owner = ActivityUtils::child($this->element, Activity::AUTHOR, Activity::SPEC);
|
||||
$this->owner = new ActivityObject($owner);
|
||||
}
|
||||
}
|
||||
|
||||
private function _fromAuthor($element)
|
||||
@ -520,13 +526,29 @@ class ActivityObject
|
||||
AVATAR_MINI_SIZE);
|
||||
|
||||
$object->poco = PoCo::fromGroup($group);
|
||||
|
||||
Event::handle('EndActivityObjectFromGroup', array($group, &$object));
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
static function fromPeopletag($ptag)
|
||||
{
|
||||
$object = new ActivityObject();
|
||||
if (Event::handle('StartActivityObjectFromPeopletag', array($ptag, &$object))) {
|
||||
$object->type = ActivityObject::_LIST;
|
||||
|
||||
$object->id = $ptag->getUri();
|
||||
$object->title = $ptag->tag;
|
||||
$object->summary = $ptag->description;
|
||||
$object->link = $ptag->homeUrl();
|
||||
$object->owner = Profile::staticGet('id', $ptag->tagger);
|
||||
$object->poco = PoCo::fromProfile($object->owner);
|
||||
Event::handle('EndActivityObjectFromPeopletag', array($ptag, &$object));
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
function outputTo($xo, $tag='activity:object')
|
||||
{
|
||||
if (!empty($tag)) {
|
||||
@ -585,6 +607,11 @@ class ActivityObject
|
||||
);
|
||||
}
|
||||
|
||||
if(!empty($this->owner)) {
|
||||
$owner = $this->owner->asActivityNoun(self::AUTHOR);
|
||||
$xo->raw($owner);
|
||||
}
|
||||
|
||||
if ($this->type == ActivityObject::PERSON
|
||||
|| $this->type == ActivityObject::GROUP) {
|
||||
|
||||
@ -602,6 +629,7 @@ class ActivityObject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!empty($this->geopoint)) {
|
||||
$xo->element(
|
||||
'georss:point',
|
||||
|
@ -59,6 +59,7 @@ class ActivityVerb
|
||||
const UNFAVORITE = 'http://ostatus.org/schema/1.0/unfavorite';
|
||||
const UNFOLLOW = 'http://ostatus.org/schema/1.0/unfollow';
|
||||
const LEAVE = 'http://ostatus.org/schema/1.0/leave';
|
||||
const UNTAG = 'http://ostatus.org/schema/1.0/untag';
|
||||
|
||||
// For simple profile-update pings; no content to share.
|
||||
const UPDATE_PROFILE = 'http://ostatus.org/schema/1.0/update-profile';
|
||||
|
@ -459,6 +459,32 @@ class ApiAction extends Action
|
||||
return $entry;
|
||||
}
|
||||
|
||||
function twitterListArray($list)
|
||||
{
|
||||
$profile = Profile::staticGet('id', $list->tagger);
|
||||
|
||||
$twitter_list = array();
|
||||
$twitter_list['id'] = $list->id;
|
||||
$twitter_list['name'] = $list->tag;
|
||||
$twitter_list['full_name'] = '@'.$profile->nickname.'/'.$list->tag;;
|
||||
$twitter_list['slug'] = $list->tag;
|
||||
$twitter_list['description'] = $list->description;
|
||||
$twitter_list['subscriber_count'] = $list->subscriberCount();
|
||||
$twitter_list['member_count'] = $list->taggedCount();
|
||||
$twitter_list['uri'] = $list->getUri();
|
||||
|
||||
if (isset($this->auth_user)) {
|
||||
$twitter_list['following'] = $list->hasSubscriber($this->auth_user);
|
||||
} else {
|
||||
$twitter_list['following'] = false;
|
||||
}
|
||||
|
||||
$twitter_list['mode'] = ($list->private) ? 'private' : 'public';
|
||||
$twitter_list['user'] = $this->twitterUserArray($profile, false);
|
||||
|
||||
return $twitter_list;
|
||||
}
|
||||
|
||||
function twitterRssEntryArray($notice)
|
||||
{
|
||||
$entry = array();
|
||||
@ -634,6 +660,20 @@ class ApiAction extends Action
|
||||
$this->elementEnd('group');
|
||||
}
|
||||
|
||||
function showTwitterXmlList($twitter_list)
|
||||
{
|
||||
$this->elementStart('list');
|
||||
foreach($twitter_list as $element => $value) {
|
||||
if($element == 'user') {
|
||||
$this->showTwitterXmlUser($value, 'user');
|
||||
}
|
||||
else {
|
||||
$this->element($element, null, $value);
|
||||
}
|
||||
}
|
||||
$this->elementEnd('list');
|
||||
}
|
||||
|
||||
function showTwitterXmlUser($twitter_user, $role='user', $namespaces=false)
|
||||
{
|
||||
$attrs = array();
|
||||
@ -1111,6 +1151,65 @@ class ApiAction extends Action
|
||||
$this->endDocument('xml');
|
||||
}
|
||||
|
||||
function showXmlLists($list, $next_cursor=0, $prev_cursor=0)
|
||||
{
|
||||
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('lists_list');
|
||||
$this->elementStart('lists', array('type' => 'array'));
|
||||
|
||||
if (is_array($list)) {
|
||||
foreach ($list as $l) {
|
||||
$twitter_list = $this->twitterListArray($l);
|
||||
$this->showTwitterXmlList($twitter_list);
|
||||
}
|
||||
} else {
|
||||
while ($list->fetch()) {
|
||||
$twitter_list = $this->twitterListArray($list);
|
||||
$this->showTwitterXmlList($twitter_list);
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementEnd('lists');
|
||||
|
||||
$this->element('next_cursor', null, $next_cursor);
|
||||
$this->element('previous_cursor', null, $prev_cursor);
|
||||
|
||||
$this->elementEnd('lists_list');
|
||||
$this->endDocument('xml');
|
||||
}
|
||||
|
||||
function showJsonLists($list, $next_cursor=0, $prev_cursor=0)
|
||||
{
|
||||
$this->initDocument('json');
|
||||
|
||||
$lists = array();
|
||||
|
||||
if (is_array($list)) {
|
||||
foreach ($list as $l) {
|
||||
$twitter_list = $this->twitterListArray($l);
|
||||
array_push($lists, $twitter_list);
|
||||
}
|
||||
} else {
|
||||
while ($list->fetch()) {
|
||||
$twitter_list = $this->twitterListArray($list);
|
||||
array_push($lists, $twitter_list);
|
||||
}
|
||||
}
|
||||
|
||||
$lists_list = array(
|
||||
'lists' => $lists,
|
||||
'next_cursor' => $next_cursor,
|
||||
'next_cursor_str' => strval($next_cursor),
|
||||
'previous_cursor' => $prev_cursor,
|
||||
'previous_cursor_str' => strval($prev_cursor)
|
||||
);
|
||||
|
||||
$this->showJsonObjects($lists_list);
|
||||
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
function showTwitterXmlUsers($user)
|
||||
{
|
||||
$this->initDocument('xml');
|
||||
@ -1172,6 +1271,22 @@ class ApiAction extends Action
|
||||
$this->endDocument('xml');
|
||||
}
|
||||
|
||||
function showSingleJsonList($list)
|
||||
{
|
||||
$this->initDocument('json');
|
||||
$twitter_list = $this->twitterListArray($list);
|
||||
$this->showJsonObjects($twitter_list);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
function showSingleXmlList($list)
|
||||
{
|
||||
$this->initDocument('xml');
|
||||
$twitter_list = $this->twitterListArray($list);
|
||||
$this->showTwitterXmlList($twitter_list);
|
||||
$this->endDocument('xml');
|
||||
}
|
||||
|
||||
function dateTwitter($dt)
|
||||
{
|
||||
$dateStr = date('d F Y H:i:s', strtotime($dt));
|
||||
@ -1465,6 +1580,40 @@ class ApiAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetList($user=null, $id=null)
|
||||
{
|
||||
$tagger = $this->getTargetUser($user);
|
||||
$list = null;
|
||||
|
||||
if (empty($id)) {
|
||||
$id = $this->arg('id');
|
||||
}
|
||||
|
||||
if($id) {
|
||||
if (is_numeric($id)) {
|
||||
$list = Profile_list::staticGet('id', $id);
|
||||
|
||||
// only if the list with the id belongs to the tagger
|
||||
if(empty($list) || $list->tagger != $tagger->id) {
|
||||
$list = null;
|
||||
}
|
||||
}
|
||||
if (empty($list)) {
|
||||
$tag = common_canonical_tag($id);
|
||||
$list = Profile_list::getByTaggerAndTag($tagger->id, $tag);
|
||||
}
|
||||
|
||||
if (!empty($list) && $list->private) {
|
||||
if ($this->auth_user->id == $list->tagger) {
|
||||
return $list;
|
||||
}
|
||||
} else {
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns query argument or default value if not found. Certain
|
||||
* parameters used throughout the API are lightly scrubbed and
|
||||
|
207
lib/apilistusers.php
Normal file
207
lib/apilistusers.php
Normal file
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base class for list members and list subscribers api.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
class ApiListUsersAction extends ApiBareAuthAction
|
||||
{
|
||||
var $list = null;
|
||||
var $user = false;
|
||||
var $create = false;
|
||||
var $delete = false;
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $users = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
// delete list member if method is DELETE or if method is POST and an argument
|
||||
// _method is set to DELETE
|
||||
$this->delete = ($_SERVER['REQUEST_METHOD'] == 'DELETE' ||
|
||||
($this->trimmed('_method') == 'DELETE' &&
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST'));
|
||||
|
||||
// add member if method is POST
|
||||
$this->create = (!$this->delete &&
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST');
|
||||
|
||||
if($this->arg('id')) {
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
}
|
||||
|
||||
parent::prepare($args);
|
||||
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
$this->clientError(_('Not found'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$this->create && !$this->delete) {
|
||||
$this->getUsers();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if($this->delete) {
|
||||
return $this->handleDelete();
|
||||
}
|
||||
|
||||
if($this->create) {
|
||||
return $this->handlePost();
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('users_list', array('xmlns:statusnet' =>
|
||||
'http://status.net/schema/api/1/'));
|
||||
$this->elementStart('users', array('type' => 'array'));
|
||||
|
||||
if (is_array($this->users)) {
|
||||
foreach ($this->users as $u) {
|
||||
$twitter_user = $this->twitterUserArray($u, true);
|
||||
$this->showTwitterXmlUser($twitter_user);
|
||||
}
|
||||
} else {
|
||||
while ($this->users->fetch()) {
|
||||
$twitter_user = $this->twitterUserArray($this->users, true);
|
||||
$this->showTwitterXmlUser($twitter_user);
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementEnd('users');
|
||||
$this->element('next_cursor', null, $this->next_cursor);
|
||||
$this->element('previous_cursor', null, $this->prev_cursor);
|
||||
$this->elementEnd('users_list');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
|
||||
$users = array();
|
||||
|
||||
if (is_array($this->users)) {
|
||||
foreach ($this->users as $u) {
|
||||
$twitter_user = $this->twitterUserArray($u, true);
|
||||
array_push($users, $twitter_user);
|
||||
}
|
||||
} else {
|
||||
while ($this->users->fetch()) {
|
||||
$twitter_user = $this->twitterUserArray($this->users, true);
|
||||
array_push($users, $twitter_user);
|
||||
}
|
||||
}
|
||||
|
||||
$users_list = array('users' => $users,
|
||||
'next_cursor' => $this->next_cursor,
|
||||
'next_cursor_str' => strval($this->next_cursor),
|
||||
'previous_cursor' => $this->prev_cursor,
|
||||
'previous_cursor_str' => strval($this->prev_cursor));
|
||||
|
||||
$this->showJsonObjects($users_list);
|
||||
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
}
|
||||
|
||||
function handleDelete()
|
||||
{
|
||||
}
|
||||
|
||||
function getUsers()
|
||||
{
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if(!empty($this->list)) {
|
||||
return strtotime($this->list->modified);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->list)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->list->id,
|
||||
strtotime($this->list->created),
|
||||
strtotime($this->list->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
105
lib/atomlistnoticefeed.php
Normal file
105
lib/atomlistnoticefeed.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Class for building an in-memory Atom feed for a particular list's
|
||||
* timeline.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Feed
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET'))
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for list notice feeds. May contain a reference to the list.
|
||||
*
|
||||
* @category Feed
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AtomListNoticeFeed extends AtomNoticeFeed
|
||||
{
|
||||
private $list;
|
||||
private $tagger;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param List $list the list for the feed
|
||||
* @param User $cur the current authenticated user, if any
|
||||
* @param boolean $indent flag to turn indenting on or off
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct($list, $cur = null, $indent = true) {
|
||||
parent::__construct($cur, $indent);
|
||||
$this->list = $list;
|
||||
$this->tagger = Profile::staticGet('id', $list->tagger);
|
||||
|
||||
// TRANS: Title in atom list notice feed. %s is a list name.
|
||||
$title = sprintf(_("Timeline for people tagged #%s by %s"), $list->tag, $this->tagger->nickname);
|
||||
$this->setTitle($title);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Message is used as a subtitle in atom list notice feed.
|
||||
// TRANS: %1$s is a list name, %2$s is a site name.
|
||||
_('Updates from %1$s\'s %2$s people tag on %3$s!'),
|
||||
$this->tagger->nickname,
|
||||
$list->tag,
|
||||
$sitename
|
||||
);
|
||||
$this->setSubtitle($subtitle);
|
||||
|
||||
$avatar = $this->tagger->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$this->setLogo($avatar);
|
||||
|
||||
$this->setUpdated('now');
|
||||
|
||||
$self = common_local_url('ApiTimelineList',
|
||||
array('user' => $this->tagger->nickname,
|
||||
'id' => $list->tag,
|
||||
'format' => 'atom'));
|
||||
$this->setId($self);
|
||||
$this->setSelfLink($self);
|
||||
|
||||
// FIXME: Stop using activity:subject?
|
||||
$ao = ActivityObject::fromPeopletag($this->list);
|
||||
|
||||
$this->addAuthorRaw($ao->asString('author').
|
||||
$ao->asString('activity:subject'));
|
||||
|
||||
$this->addLink($this->list->getUri());
|
||||
}
|
||||
|
||||
function getList()
|
||||
{
|
||||
return $this->list;
|
||||
}
|
||||
|
||||
}
|
102
lib/command.php
102
lib/command.php
@ -414,6 +414,104 @@ class DropCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
class TagCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
var $tags = null;
|
||||
function __construct($user, $other, $tags)
|
||||
{
|
||||
parent::__construct($user);
|
||||
$this->other = $other;
|
||||
$this->tags = $tags;
|
||||
}
|
||||
|
||||
function handle($channel)
|
||||
{
|
||||
$profile = $this->getProfile($this->other);
|
||||
$cur = $this->user->getProfile();
|
||||
|
||||
if (!$profile) {
|
||||
$channel->error($cur, _('No such profile.'));
|
||||
return;
|
||||
}
|
||||
if (!$cur->canTag($profile)) {
|
||||
$channel->error($cur, _('You cannot tag this user.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$privs = array();
|
||||
$tags = preg_split('/[\s,]+/', $this->tags);
|
||||
$clean_tags = array();
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$private = @$tag[0] === '.';
|
||||
$tag = $clean_tags[] = common_canonical_tag($tag);
|
||||
|
||||
if (!common_valid_profile_tag($tag)) {
|
||||
$channel->error($cur, sprintf(_('Invalid tag: "%s"'), $tag));
|
||||
return;
|
||||
}
|
||||
$privs[$tag] = $private;
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($clean_tags as $tag) {
|
||||
Profile_tag::setTag($cur->id, $profile->id, $tag, null, $privs[$tag]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$channel->error($cur, sprintf(_('Error tagging %s: %s'),
|
||||
$profile->nickname, $e->getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
$channel->output($cur, sprintf(_('%1$s was tagged %2$s'),
|
||||
$profile->nickname,
|
||||
implode(', ', $clean_tags)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UntagCommand extends TagCommand
|
||||
{
|
||||
function handle($channel)
|
||||
{
|
||||
$profile = $this->getProfile($this->other);
|
||||
$cur = $this->user->getProfile();
|
||||
|
||||
if (!$profile) {
|
||||
$channel->error($cur, _('No such profile.'));
|
||||
return;
|
||||
}
|
||||
if (!$cur->canTag($profile)) {
|
||||
$channel->error($cur, _('You cannot tag this user.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $this->tags));
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
if (!common_valid_profile_tag($tag)) {
|
||||
$channel->error($cur, sprintf(_('Invalid tag: "%s"'), $tag));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($tags as $tag) {
|
||||
Profile_tag::unTag($cur->id, $profile->id, $tag);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$channel->error($cur, sprintf(_('Error untagging %s: %s'),
|
||||
$profile->nickname, $e->getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
$channel->output($cur, sprintf(_('The following tag(s) were removed from user %1$s: %2$s.'),
|
||||
$profile->nickname,
|
||||
implode(', ', $tags)));
|
||||
}
|
||||
}
|
||||
|
||||
class WhoisCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
@ -903,6 +1001,10 @@ class HelpCommand extends Command
|
||||
"follow <nickname>" => _m('COMMANDHELP', "subscribe to user"),
|
||||
// TRANS: Help message for IM/SMS command "groups"
|
||||
"groups" => _m('COMMANDHELP', "lists the groups you have joined"),
|
||||
// TRANS: Help message for IM/SMS command "tag"
|
||||
"tag <nickname> <tags>" => _m('COMMANDHELP',"tag a user"),
|
||||
// TRANS: Help message for IM/SMS command "untag"
|
||||
"untag <nickname> <tags>" => _m('COMMANDHELP',"untag a user"),
|
||||
// TRANS: Help message for IM/SMS command "subscriptions"
|
||||
"subscriptions" => _m('COMMANDHELP', "list the people you follow"),
|
||||
// TRANS: Help message for IM/SMS command "subscribers"
|
||||
|
@ -274,6 +274,32 @@ class CommandInterpreter
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'list':
|
||||
case 'tag':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
break;
|
||||
}
|
||||
list($other, $tags) = $this->split_arg($arg);
|
||||
if (!$tags) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new TagCommand($user, $other, $tags);
|
||||
}
|
||||
break;
|
||||
case 'unlist':
|
||||
case 'untag':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
break;
|
||||
}
|
||||
list($other, $tags) = $this->split_arg($arg);
|
||||
if (!$tags) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new UntagCommand($user, $other, $tags);
|
||||
}
|
||||
break;
|
||||
case 'track':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
|
@ -269,6 +269,11 @@ $default =
|
||||
'group' =>
|
||||
array('maxaliases' => 3,
|
||||
'desclimit' => null),
|
||||
'peopletag' =>
|
||||
array('maxtags' => 100, // maximum number of tags a user can create.
|
||||
'maxpeople' => 500, // maximum no. of people with the same tag by the same user
|
||||
'allow_tagging' => array('all' => true), // equivalent to array('local' => true, 'remote' => true)
|
||||
'desclimit' => null),
|
||||
'oembed' =>
|
||||
array('endpoint' => 'http://oohembed.com/oohembed/',
|
||||
'order' => array('built-in', 'well-known', 'service', 'discovery'),
|
||||
|
@ -46,6 +46,7 @@ define('NOTICE_INBOX_SOURCE_SUB', 1);
|
||||
define('NOTICE_INBOX_SOURCE_GROUP', 2);
|
||||
define('NOTICE_INBOX_SOURCE_REPLY', 3);
|
||||
define('NOTICE_INBOX_SOURCE_FORWARD', 4);
|
||||
define('NOTICE_INBOX_SOURCE_PROFILE_TAG', 5);
|
||||
define('NOTICE_INBOX_SOURCE_GATEWAY', -1);
|
||||
|
||||
// append our extlib dir as the last-resort place to find libs
|
||||
|
@ -120,6 +120,9 @@ class GalleryAction extends OwnerDesignAction
|
||||
$content[$t] = $t;
|
||||
}
|
||||
if ($tags) {
|
||||
$this->elementStart('dl', array('id' => 'filter_tags'));
|
||||
$this->element('dt', null, _('Tags'));
|
||||
$this->elementStart('dd');
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', array('id' => 'filter_tags_all',
|
||||
'class' => 'child_1'));
|
||||
@ -150,6 +153,8 @@ class GalleryAction extends OwnerDesignAction
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
}
|
||||
|
||||
|
200
lib/peopletageditform.php
Normal file
200
lib/peopletageditform.php
Normal file
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for editing 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 Form
|
||||
* @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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
require_once INSTALLDIR.'/lib/togglepeopletag.php';
|
||||
|
||||
/**
|
||||
* Form for editing a peopletag
|
||||
*
|
||||
* @category Form
|
||||
* @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/
|
||||
*
|
||||
* @see GroupEditForm
|
||||
*/
|
||||
|
||||
class PeopletagEditForm extends Form
|
||||
{
|
||||
/**
|
||||
* peopletag to edit
|
||||
*/
|
||||
|
||||
var $peopletag = null;
|
||||
var $tagger = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Action $out output channel
|
||||
* @param User_group $group group to join
|
||||
*/
|
||||
|
||||
function __construct($out=null, Profile_list $peopletag=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->peopletag = $peopletag;
|
||||
$this->tagger = Profile::staticGet('id', $peopletag->tagger);
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_peopletag_edit-' . $this->peopletag->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('editpeopletag',
|
||||
array('tagger' => $this->tagger->nickname, 'tag' => $this->peopletag->tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, sprintf(_('Edit peopletag %s'), $this->peopletag->tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$id = $this->peopletag->id;
|
||||
$tag = $this->peopletag->tag;
|
||||
$description = $this->peopletag->description;
|
||||
$private = $this->peopletag->private;
|
||||
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->hidden('id', $id);
|
||||
$this->out->input('tag', _('Tag'),
|
||||
($this->out->arg('tag')) ? $this->out->arg('tag') : $tag,
|
||||
_('Change the tag (letters, numbers, -, ., and _ are allowed)'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$desclimit = Profile_list::maxDescription();
|
||||
if ($desclimit == 0) {
|
||||
$descinstr = _('Describe the people tag or topic');
|
||||
} else {
|
||||
$descinstr = sprintf(_('Describe the people tag or topic in %d characters'), $desclimit);
|
||||
}
|
||||
$this->out->textarea('description', _('Description'),
|
||||
($this->out->arg('description')) ? $this->out->arg('description') : $description,
|
||||
$descinstr);
|
||||
$this->out->checkbox('private', _('Private'), $private);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Save'));
|
||||
$this->out->submit('form_action-yes',
|
||||
_m('BUTTON','Delete'),
|
||||
'submit',
|
||||
'delete',
|
||||
_('Delete this people tag'));
|
||||
}
|
||||
|
||||
function showProfileList()
|
||||
{
|
||||
$tagged = $this->peopletag->getTagged();
|
||||
$this->out->element('h2', null, 'Add or remove people');
|
||||
|
||||
$this->out->elementStart('div', 'profile_search_wrap');
|
||||
$this->out->element('h3', null, _m('BUTTON', 'Search'));
|
||||
$search = new SearchProfileForm($this->out, $this->peopletag);
|
||||
$search->show();
|
||||
$this->out->element('ul', array('id' => 'profile_search_results', 'class' => 'empty'));
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
$this->out->elementStart('ul', 'profile-lister');
|
||||
while ($tagged->fetch()) {
|
||||
$this->out->elementStart('li', 'entity_removable_profile');
|
||||
$this->showProfileItem($tagged);
|
||||
$this->out->elementStart('span', 'entity_actions');
|
||||
$untag = new UntagButton($this->out, $tagged, $this->peopletag);
|
||||
$untag->show();
|
||||
$this->out->elementEnd('span');
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
|
||||
function showProfileItem($profile)
|
||||
{
|
||||
$item = new TaggedProfileItem($this->out, $profile);
|
||||
$item->show();
|
||||
}
|
||||
}
|
145
lib/peopletaggroupnav.php
Normal file
145
lib/peopletaggroupnav.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base class for all actions (~views)
|
||||
*
|
||||
* 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 Sarven Capadisli <csarven@status.net>
|
||||
* @copyright 2008 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/widget.php';
|
||||
|
||||
/**
|
||||
* Base class for all actions
|
||||
*
|
||||
* This is the base class for all actions in the package. An action is
|
||||
* more or less a "view" in an MVC framework.
|
||||
*
|
||||
* Actions are responsible for extracting and validating parameters; using
|
||||
* model classes to read and write to the database; and doing ouput.
|
||||
*
|
||||
* @category Output
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see HTMLOutputter
|
||||
*/
|
||||
|
||||
class PeopletagGroupNav extends Widget
|
||||
{
|
||||
var $action = null;
|
||||
|
||||
/**
|
||||
* Construction
|
||||
*
|
||||
* @param Action $action current action, used for output
|
||||
*/
|
||||
|
||||
function __construct($action=null)
|
||||
{
|
||||
parent::__construct($action);
|
||||
$this->action = $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
$user = null;
|
||||
|
||||
// FIXME: we should probably pass this in
|
||||
|
||||
$action = $this->action->trimmed('action');
|
||||
$nickname = $this->action->trimmed('tagger');
|
||||
$tag = $this->action->trimmed('tag');
|
||||
|
||||
if ($nickname) {
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
$user_profile = $user->getProfile();
|
||||
|
||||
if ($tag) {
|
||||
$tag = Profile_list::pkeyGet(array('tagger' => $user->id,
|
||||
'tag' => $tag));
|
||||
} else {
|
||||
$tag = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
$user_profile = false;
|
||||
}
|
||||
|
||||
$this->out->elementStart('ul', array('class' => 'nav'));
|
||||
|
||||
if (Event::handle('StartPeopletagGroupNav', array($this))) {
|
||||
// People tag timeline
|
||||
$this->out->menuItem(common_local_url('showprofiletag', array('tagger' => $user_profile->nickname,
|
||||
'tag' => $tag->tag)),
|
||||
_('People tag'),
|
||||
sprintf(_('%s tag by %s'), $tag->tag,
|
||||
(($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'showprofiletag', 'nav_timeline_peopletag');
|
||||
|
||||
// Tagged
|
||||
$this->out->menuItem(common_local_url('peopletagged', array('tagger' => $user->nickname,
|
||||
'tag' => $tag->tag)),
|
||||
_('Tagged'),
|
||||
sprintf(_('%s tag by %s'), $tag->tag,
|
||||
(($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'peopletagged', 'nav_peopletag_tagged');
|
||||
|
||||
// Subscribers
|
||||
$this->out->menuItem(common_local_url('peopletagsubscribers', array('tagger' => $user->nickname,
|
||||
'tag' => $tag->tag)),
|
||||
_('Subscribers'),
|
||||
sprintf(_('Subscribers to %s tag by %s'), $tag->tag,
|
||||
(($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'peopletagsubscribers', 'nav_peopletag_subscribers');
|
||||
|
||||
$cur = common_current_user();
|
||||
if (!empty($cur) && $user_profile->id == $cur->id) {
|
||||
// Edit
|
||||
$this->out->menuItem(common_local_url('editpeopletag', array('tagger' => $user->nickname,
|
||||
'tag' => $tag->tag)),
|
||||
_('Edit'),
|
||||
sprintf(_('Edit %s tag by you'), $tag->tag,
|
||||
(($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'editpeopletag', 'nav_peopletag_edit');
|
||||
}
|
||||
|
||||
Event::handle('EndPeopletagGroupNav', array($this));
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
}
|
320
lib/peopletaglist.php
Normal file
320
lib/peopletaglist.php
Normal file
@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Widget to show a list of peopletags
|
||||
*
|
||||
* 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 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/widget.php';
|
||||
|
||||
define('PEOPLETAGS_PER_PAGE', 20);
|
||||
|
||||
/**
|
||||
* Widget to show a list of peopletags
|
||||
*
|
||||
* @category Public
|
||||
* @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 PeopletagList extends Widget
|
||||
{
|
||||
/** Current peopletag, peopletag query. */
|
||||
var $peopletag = null;
|
||||
/** current user **/
|
||||
var $user = null;
|
||||
|
||||
function __construct($peopletag, $action=null)
|
||||
{
|
||||
parent::__construct($action);
|
||||
|
||||
$this->peopletag = $peopletag;
|
||||
|
||||
if (!empty($owner)) {
|
||||
$this->user = $owner;
|
||||
} else {
|
||||
$this->user = common_current_user();
|
||||
}
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->out->elementStart('ul', 'peopletags xoxo hfeed');
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
while ($this->peopletag->fetch()) {
|
||||
$cnt++;
|
||||
if($cnt > PEOPLETAGS_PER_PAGE) {
|
||||
break;
|
||||
}
|
||||
$this->showPeopletag();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
function showPeopletag()
|
||||
{
|
||||
$ptag = new PeopletagListItem($this->peopletag, $this->user, $this->out);
|
||||
$ptag->show();
|
||||
}
|
||||
}
|
||||
|
||||
class PeopletagListItem extends Widget
|
||||
{
|
||||
var $peopletag = null;
|
||||
var $current = null;
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* Also initializes the owner attribute.
|
||||
*
|
||||
* @param Notice $notice The notice we'll display
|
||||
*/
|
||||
|
||||
function __construct($peopletag, $current, $out=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->peopletag = $peopletag;
|
||||
$this->current = $current;
|
||||
$this->profile = Profile::staticGet('id', $this->peopletag->tagger);
|
||||
}
|
||||
|
||||
/**
|
||||
* recipe function for displaying a single peopletag.
|
||||
*
|
||||
* This uses all the other methods to correctly display a notice. Override
|
||||
* it or one of the others to fine-tune the output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function url()
|
||||
{
|
||||
return $this->peopletag->homeUrl();
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
if (empty($this->peopletag)) {
|
||||
common_log(LOG_WARNING, "Trying to show missing peopletag; skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Event::handle('StartShowPeopletagItem', array($this))) {
|
||||
$this->showStart();
|
||||
$this->showPeopletag();
|
||||
$this->showStats();
|
||||
$this->showEnd();
|
||||
Event::handle('EndShowPeopletagItem', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
function showStart()
|
||||
{
|
||||
$mode = ($this->peopletag->private) ? 'private' : 'public';
|
||||
$this->out->elementStart('li', array('class' => 'hentry peopletag mode-' . $mode,
|
||||
'id' => 'peopletag-' . $this->peopletag->id));
|
||||
}
|
||||
|
||||
function showEnd()
|
||||
{
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
|
||||
function showPeopletag()
|
||||
{
|
||||
$this->showCreator();
|
||||
$this->showTag();
|
||||
$this->showPrivacy();
|
||||
$this->showUpdated();
|
||||
$this->showActions();
|
||||
$this->showDescription();
|
||||
}
|
||||
|
||||
function showStats()
|
||||
{
|
||||
$this->out->elementStart('div', 'entry-summary entity_statistics');
|
||||
$this->out->elementStart('span', 'tagged-count');
|
||||
$this->out->element('a',
|
||||
array('href' => common_local_url('peopletagged',
|
||||
array('tagger' => $this->profile->nickname,
|
||||
'tag' => $this->peopletag->tag))),
|
||||
_('Tagged'));
|
||||
$this->out->raw($this->peopletag->taggedCount());
|
||||
$this->out->elementEnd('span');
|
||||
|
||||
$this->out->elementStart('span', 'subscriber-count');
|
||||
$this->out->element('a',
|
||||
array('href' => common_local_url('peopletagsubscribers',
|
||||
array('tagger' => $this->profile->nickname,
|
||||
'tag' => $this->peopletag->tag))),
|
||||
_('Subscribers'));
|
||||
$this->out->raw($this->peopletag->subscriberCount());
|
||||
$this->out->elementEnd('span');
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
|
||||
function showOwnerOptions()
|
||||
{
|
||||
$this->out->elementStart('li', 'entity_edit');
|
||||
$this->out->element('a', array('href' =>
|
||||
common_local_url('editpeopletag', array('tagger' => $this->profile->nickname,
|
||||
'tag' => $this->peopletag->tag)),
|
||||
'title' => _('Edit peopletag settings')),
|
||||
_('Edit'));
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
|
||||
function showSubscribeForm()
|
||||
{
|
||||
$this->out->elementStart('li');
|
||||
|
||||
if (Event::handle('StartSubscribePeopletagForm', array($this->out, $this->peopletag))) {
|
||||
if ($this->current) {
|
||||
if ($this->peopletag->hasSubscriber($this->current->id)) {
|
||||
$form = new UnsubscribePeopletagForm($this->out, $this->peopletag);
|
||||
$form->show();
|
||||
} else {
|
||||
$form = new SubscribePeopletagForm($this->out, $this->peopletag);
|
||||
$form->show();
|
||||
}
|
||||
}
|
||||
Event::handle('EndSubscribePeopletagForm', array($this->out, $this->peopletag));
|
||||
}
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
|
||||
function showCreator()
|
||||
{
|
||||
$this->out->elementStart('span', 'author vcard');
|
||||
$attrs = array();
|
||||
$attrs['href'] = $this->profile->profileurl;
|
||||
$attrs['class'] = 'url';
|
||||
$attrs['rel'] = 'contact';
|
||||
|
||||
if (!empty($this->profile->fullname)) {
|
||||
$attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ')';
|
||||
}
|
||||
$this->out->elementStart('a', $attrs);
|
||||
$this->showAvatar();
|
||||
$this->out->text(' ');
|
||||
$this->out->element('span', 'nickname fn',
|
||||
htmlspecialchars($this->profile->nickname));
|
||||
|
||||
$this->out->elementEnd('a');
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
|
||||
function showUpdated()
|
||||
{
|
||||
if (!empty($this->peopletag->modified)) {
|
||||
$this->out->element('abbr',
|
||||
array('title' => common_date_w3dtf($this->peopletag->modified),
|
||||
'class' => 'updated'),
|
||||
common_date_string($this->peopletag->modified));
|
||||
}
|
||||
}
|
||||
|
||||
function showPrivacy()
|
||||
{
|
||||
if ($this->peopletag->private) {
|
||||
$this->out->elementStart('a',
|
||||
array('href' => common_local_url('peopletagsbyuser',
|
||||
array('nickname' => $this->profile->nickname, 'private' => 1))));
|
||||
$this->out->element('span', 'privacy_mode', _('Private'));
|
||||
$this->out->elementEnd('a');
|
||||
}
|
||||
}
|
||||
|
||||
function showTag()
|
||||
{
|
||||
$this->out->elementStart('span', 'entry-title tag');
|
||||
$this->out->element('a',
|
||||
array('rel' => 'bookmark',
|
||||
'href' => $this->url()),
|
||||
htmlspecialchars($this->peopletag->tag));
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
|
||||
/**
|
||||
* show the avatar of the peopletag's creator
|
||||
*
|
||||
* This will use the default avatar if no avatar is assigned for the author.
|
||||
* It makes a link to the author's profile.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showAvatar($size=AVATAR_STREAM_SIZE)
|
||||
{
|
||||
$avatar = $this->profile->getAvatar($size);
|
||||
|
||||
$this->out->element('img', array('src' => ($avatar) ?
|
||||
$avatar->displayUrl() :
|
||||
Avatar::defaultImage($size),
|
||||
'class' => 'avatar photo',
|
||||
'width' => $size,
|
||||
'height' => $size,
|
||||
'alt' =>
|
||||
($this->profile->fullname) ?
|
||||
$this->profile->fullname :
|
||||
$this->profile->nickname));
|
||||
}
|
||||
|
||||
function showActions()
|
||||
{
|
||||
$this->out->elementStart('div', 'entity_actions');
|
||||
$this->out->elementStart('ul');
|
||||
|
||||
if (!$this->peopletag->private) {
|
||||
$this->showSubscribeForm();
|
||||
}
|
||||
|
||||
if (!empty($this->current) && $this->profile->id == $this->current->id) {
|
||||
$this->showOwnerOptions();
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
|
||||
function showDescription()
|
||||
{
|
||||
$this->out->element('div', 'entry-content description',
|
||||
$this->peopletag->description);
|
||||
}
|
||||
}
|
105
lib/peopletagnoticestream.php
Normal file
105
lib/peopletagnoticestream.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Stream of notices for a people tag
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of notices for a people tag
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class PeopletagNoticeStream extends ScopingNoticeStream
|
||||
{
|
||||
function __construct($plist)
|
||||
{
|
||||
parent::__construct(new CachingNoticeStream(new RawPeopletagNoticeStream($plist),
|
||||
'profile_tag:notice_ids:' . $plist->id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of notices for a people tag
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RawPeopletagNoticeStream extends NoticeStream
|
||||
{
|
||||
protected $profile_tag;
|
||||
|
||||
function __construct($profile_tag)
|
||||
{
|
||||
$this->profile_tag = $profile_tag;
|
||||
}
|
||||
|
||||
function getNoticeIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$inbox = new Profile_tag_inbox();
|
||||
|
||||
$inbox->profile_tag_id = $this->profile_tag->id;
|
||||
|
||||
$inbox->selectAdd();
|
||||
$inbox->selectAdd('notice_id');
|
||||
|
||||
Notice::addWhereSinceId($inbox, $since_id, 'notice_id');
|
||||
Notice::addWhereMaxId($inbox, $max_id, 'notice_id');
|
||||
|
||||
$inbox->orderBy('created DESC, notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$inbox->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($inbox->find()) {
|
||||
while ($inbox->fetch()) {
|
||||
$ids[] = $inbox->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
191
lib/peopletags.php
Normal file
191
lib/peopletags.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Tags for a profile
|
||||
*
|
||||
* 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
|
||||
* @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/widget.php';
|
||||
|
||||
/*
|
||||
* Show a bunch of peopletags
|
||||
* provide ajax editing if the current user owns the tags
|
||||
*
|
||||
* @category Action
|
||||
* @pacage 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
|
||||
*/
|
||||
|
||||
class PeopletagsWidget extends Widget
|
||||
{
|
||||
/*
|
||||
* the query, current peopletag.
|
||||
* or an array of strings (tags)
|
||||
*/
|
||||
|
||||
var $tag=null;
|
||||
|
||||
var $user=null;
|
||||
var $tagger=null;
|
||||
var $tagged=null;
|
||||
|
||||
function __construct($out, $tagger, $tagged)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->user = common_current_user();
|
||||
$this->tag = Profile_tag::getTags($tagger->id, $tagged->id, $this->user);
|
||||
$this->tagger = $tagger;
|
||||
$this->tagged = $tagged;
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
if (Event::handle('StartShowPeopletags', array($this, $this->tagger, $this->tagged))) {
|
||||
if ($this->tag->N > 0) {
|
||||
$this->showTags();
|
||||
}
|
||||
else {
|
||||
$this->showEmptyList();
|
||||
}
|
||||
Event::handle('EndShowPeopletags', array($this, $this->tagger, $this->tagged));
|
||||
}
|
||||
}
|
||||
|
||||
function url()
|
||||
{
|
||||
return $this->tag->homeUrl();
|
||||
}
|
||||
|
||||
function label()
|
||||
{
|
||||
return _('Tags by you');
|
||||
}
|
||||
|
||||
function showTags()
|
||||
{
|
||||
$this->out->elementStart('dl', 'entity_tags user_profile_tags');
|
||||
$this->out->element('dt', null, $this->label());
|
||||
$this->out->elementStart('dd');
|
||||
|
||||
$class = 'tags xoxo';
|
||||
if ($this->isEditable()) {
|
||||
$class .= ' editable';
|
||||
}
|
||||
|
||||
$tags = array();
|
||||
$this->out->elementStart('ul', $class);
|
||||
while ($this->tag->fetch()) {
|
||||
$mode = $this->tag->private ? 'private' : 'public';
|
||||
$tags[] = $this->tag->tag;
|
||||
|
||||
$this->out->elementStart('li', 'hashptag mode-' . $mode);
|
||||
// Avoid space by using raw output.
|
||||
$pt = '<span class="mark_hash">#</span><a rel="tag" href="' .
|
||||
$this->url($this->tag->tag) .
|
||||
'">' . $this->tag->tag . '</a>';
|
||||
$this->out->raw($pt);
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
if ($this->isEditable()) {
|
||||
$this->showEditTagForm($tags);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('dd');
|
||||
$this->out->elementEnd('dl');
|
||||
}
|
||||
|
||||
function showEditTagForm($tags=null)
|
||||
{
|
||||
$this->out->elementStart('span', 'form_tag_user_wrap');
|
||||
$this->out->elementStart('form', array('method' => 'post',
|
||||
'class' => 'form_tag_user',
|
||||
'name' => 'tagprofile',
|
||||
'action' => common_local_url('tagprofile', array('id' => $this->tagged->id))));
|
||||
|
||||
$this->out->elementStart('fieldset');
|
||||
$this->out->element('legend', null, _('Edit tags'));
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->hidden('id', $this->tagged->id);
|
||||
|
||||
if (!$tags) {
|
||||
$tags = array();
|
||||
}
|
||||
|
||||
$this->out->input('tags', $this->label(),
|
||||
($this->out->arg('tags')) ? $this->out->arg('tags') : implode(' ', $tags));
|
||||
$this->out->submit('save', _('Save'));
|
||||
|
||||
$this->out->elementEnd('fieldset');
|
||||
$this->out->elementEnd('form');
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
|
||||
function showEmptyList()
|
||||
{
|
||||
$this->out->elementStart('dl', 'entity_tags user_profile_tags');
|
||||
$this->out->element('dt', null, $this->label());
|
||||
$this->out->elementStart('dd');
|
||||
|
||||
$class = 'tags';
|
||||
if ($this->isEditable()) {
|
||||
$class .= ' editable';
|
||||
}
|
||||
|
||||
$this->out->elementStart('ul', $class);
|
||||
$this->out->element('li', null, _('(None)'));
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
if ($this->isEditable()) {
|
||||
$this->showEditTagForm();
|
||||
}
|
||||
$this->out->elementEnd('dd');
|
||||
$this->out->elementEnd('dl');
|
||||
}
|
||||
|
||||
function isEditable()
|
||||
{
|
||||
return !empty($this->user) && $this->tagger->id == $this->user->id;
|
||||
}
|
||||
}
|
||||
|
||||
class SelftagsWidget extends PeopletagsWidget
|
||||
{
|
||||
function url($tag)
|
||||
{
|
||||
// link to self tag page
|
||||
return common_local_url('selftag', array('tag' => $tag));
|
||||
}
|
||||
|
||||
function label()
|
||||
{
|
||||
return _('Tags');
|
||||
}
|
||||
}
|
76
lib/peopletagsbysubssection.php
Normal file
76
lib/peopletagsbysubssection.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Peopletags with the most subscribers section
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Widget
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peopletags with the most subscribers section
|
||||
*
|
||||
* @category Widget
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class PeopletagsBySubsSection extends PeopletagSection
|
||||
{
|
||||
function getPeopletags()
|
||||
{
|
||||
$qry = 'SELECT profile_list.*, subscriber_count as value ' .
|
||||
'FROM profile_list WHERE profile_list.private = false ' .
|
||||
'ORDER BY value DESC ';
|
||||
|
||||
$limit = PEOPLETAGS_PER_SECTION;
|
||||
$offset = 0;
|
||||
|
||||
if (common_config('db','type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
|
||||
$peopletag = Memcached_DataObject::cachedQuery('Profile_list',
|
||||
$qry,
|
||||
3600);
|
||||
return $peopletag;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('People tags with most subscribers');
|
||||
}
|
||||
|
||||
function divId()
|
||||
{
|
||||
return 'top_peopletags_by_subs';
|
||||
}
|
||||
}
|
139
lib/peopletagsection.php
Normal file
139
lib/peopletagsection.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base class for sections showing lists of peopletags
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Widget
|
||||
* @package StatusNet
|
||||
* @author 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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/peopletaglist.php';
|
||||
|
||||
define('PEOPLETAGS_PER_SECTION', 6);
|
||||
|
||||
/**
|
||||
* Base class for sections
|
||||
*
|
||||
* These are the widgets that show interesting data about a person
|
||||
* peopletag, or site.
|
||||
*
|
||||
* @category Widget
|
||||
* @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 PeopletagSection extends Section
|
||||
{
|
||||
function showContent()
|
||||
{
|
||||
$tags = $this->getPeopletags();
|
||||
|
||||
if (!$tags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
$this->out->elementStart('table', 'peopletag_section');
|
||||
|
||||
while ($tags->fetch() && ++$cnt <= PEOPLETAGS_PER_SECTION) {
|
||||
$this->showPeopletag($tags);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('table');
|
||||
|
||||
return ($cnt > PEOPLETAGS_PER_SECTION);
|
||||
}
|
||||
|
||||
function getPeopletags()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
function showPeopletag($peopletag)
|
||||
{
|
||||
$tag = new PeopletagSectionItem($peopletag, null, $this->out);
|
||||
$tag->show();
|
||||
}
|
||||
}
|
||||
|
||||
class PeopletagSectionItem extends PeopletagListItem
|
||||
{
|
||||
function showStart()
|
||||
{
|
||||
}
|
||||
|
||||
function showEnd()
|
||||
{
|
||||
}
|
||||
|
||||
function showPeopletag()
|
||||
{
|
||||
$this->showCreator();
|
||||
$this->showTag();
|
||||
$this->showPrivacy();
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
if (empty($this->peopletag)) {
|
||||
common_log(LOG_WARNING, "Trying to show missing peopletag; skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out->elementStart('tr');
|
||||
|
||||
$this->out->elementStart('td', 'peopletag');
|
||||
$this->showPeopletag();
|
||||
$this->out->elementEnd('td');
|
||||
|
||||
if (isset($this->peopletag->value)) {
|
||||
$this->out->element('td', 'value', $this->peopletag->value);
|
||||
}
|
||||
$this->out->elementEnd('tr');
|
||||
}
|
||||
|
||||
function showTag()
|
||||
{
|
||||
$title = _('Tagged: ') . $this->peopletag->taggedCount() .
|
||||
' ' . _('Subscribers: ') . $this->peopletag->subscriberCount();
|
||||
|
||||
$this->out->elementStart('span', 'entry-title tag');
|
||||
$this->out->element('a',
|
||||
array('rel' => 'bookmark',
|
||||
'href' => $this->url(),
|
||||
'title' => $title),
|
||||
htmlspecialchars($this->peopletag->tag));
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
|
||||
function showAvatar()
|
||||
{
|
||||
parent::showAvatar(AVATAR_MINI_SIZE);
|
||||
}
|
||||
}
|
89
lib/peopletagsforusersection.php
Normal file
89
lib/peopletagsforusersection.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* People tags a user has been tagged with
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Widget
|
||||
* @package StatusNet
|
||||
* @author 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* People tags a user has been tagged with
|
||||
*
|
||||
* @category Widget
|
||||
* @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 PeopletagsForUserSection extends PeopletagSection
|
||||
{
|
||||
var $profile=null;
|
||||
|
||||
function __construct($out, Profile $profile)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->profile = $profile;
|
||||
}
|
||||
|
||||
function getPeopletags()
|
||||
{
|
||||
$limit = PEOPLETAGS_PER_SECTION+1;
|
||||
$offset = 0;
|
||||
|
||||
$auth_user = common_current_user();
|
||||
$ptags = $this->profile->getOtherTags($auth_user, $offset, $limit);
|
||||
|
||||
return $ptags;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
$name = $this->profile->getBestName();
|
||||
if ($this->profile->id == common_current_user()->id) {
|
||||
$name = 'you';
|
||||
}
|
||||
return sprintf(_('People tags for %s'), $name);
|
||||
}
|
||||
|
||||
|
||||
function link()
|
||||
{
|
||||
return common_local_url('peopletagsforuser',
|
||||
array('nickname' => $this->profile->nickname));
|
||||
}
|
||||
|
||||
function moreUrl()
|
||||
{
|
||||
return $this->link();
|
||||
}
|
||||
|
||||
function divId()
|
||||
{
|
||||
return 'peopletag_subscriptions';
|
||||
}
|
||||
}
|
83
lib/peopletagsubscriptionssection.php
Normal file
83
lib/peopletagsubscriptionssection.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Peopletags a user has subscribed to
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Widget
|
||||
* @package StatusNet
|
||||
* @author 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peopletags a user has subscribed to
|
||||
*
|
||||
* @category Widget
|
||||
* @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 PeopletagSubscriptionsSection extends PeopletagSection
|
||||
{
|
||||
var $profile=null;
|
||||
|
||||
function __construct($out, Profile $profile)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->profile = $profile;
|
||||
}
|
||||
|
||||
function getPeopletags()
|
||||
{
|
||||
$limit = PEOPLETAGS_PER_SECTION+1;
|
||||
$offset = 0;
|
||||
|
||||
$ptags = $this->profile->getTagSubscriptions($offset, $limit);
|
||||
|
||||
return $ptags;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('People tag subscriptions');
|
||||
}
|
||||
|
||||
function link()
|
||||
{
|
||||
return common_local_url('peopletagsubscriptions',
|
||||
array('nickname' => $this->profile->nickname));
|
||||
}
|
||||
|
||||
function moreUrl()
|
||||
{
|
||||
return $this->link();
|
||||
}
|
||||
|
||||
function divId()
|
||||
{
|
||||
return 'peopletag_subscriptions';
|
||||
}
|
||||
}
|
@ -103,6 +103,12 @@ class PersonalGroupNav extends Menu
|
||||
// TRANS: Replaces %s in '%s\'s favorite notices'. (Yes, we know we need to fix this.)
|
||||
($user_profile) ? $name : _m('FIXME','User')),
|
||||
$mine && $action =='showfavorites', 'nav_timeline_favorites');
|
||||
$this->out->menuItem(common_local_url('peopletagsbyuser', array('nickname' =>
|
||||
$nickname)),
|
||||
_('People tags'),
|
||||
sprintf(_('People tags by %s'), ($user_profile) ? $name : _('User')),
|
||||
in_array($action, array('peopletagsbyuser', 'peopletagsforuser')),
|
||||
'nav_timeline_peopletags');
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
|
@ -97,6 +97,8 @@ class ProfileAction extends OwnerDesignAction
|
||||
$this->showSubscriptions();
|
||||
$this->showSubscribers();
|
||||
$this->showGroups();
|
||||
$this->showPeopletagSubs();
|
||||
$this->showPeopletags();
|
||||
$this->showStatistics();
|
||||
}
|
||||
|
||||
@ -188,6 +190,32 @@ class ProfileAction extends OwnerDesignAction
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showPeopletagSubs()
|
||||
{
|
||||
$user = common_current_user();
|
||||
if (!empty($user) && $this->profile->id == $user->id) {
|
||||
if (Event::handle('StartShowPeopletagSubscriptionsSection', array($this))) {
|
||||
|
||||
$profile = $user->getProfile();
|
||||
$section = new PeopletagSubscriptionsSection($this, $profile);
|
||||
$section->show();
|
||||
|
||||
Event::handle('EndShowPeopletagSubscriptionsSection', array($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showPeopletags()
|
||||
{
|
||||
if (Event::handle('StartShowPeopletagsSection', array($this))) {
|
||||
|
||||
$section = new PeopletagsForUserSection($this, $this->profile);
|
||||
$section->show();
|
||||
|
||||
Event::handle('EndShowPeopletagsSection', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
function showStatistics()
|
||||
{
|
||||
$notice_count = $this->profile->noticeCount();
|
||||
|
@ -62,6 +62,7 @@ abstract class ProfileBlock extends Widget
|
||||
$this->showLocation();
|
||||
$this->showHomepage();
|
||||
$this->showDescription();
|
||||
$this->showTags();
|
||||
}
|
||||
|
||||
function showAvatar()
|
||||
@ -131,6 +132,10 @@ abstract class ProfileBlock extends Widget
|
||||
return AVATAR_PROFILE_SIZE;
|
||||
}
|
||||
|
||||
function showTags()
|
||||
{
|
||||
}
|
||||
|
||||
function showActions()
|
||||
{
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/widget.php';
|
||||
require_once INSTALLDIR.'/lib/peopletags.php';
|
||||
|
||||
/**
|
||||
* Widget to show a list of profiles
|
||||
@ -168,6 +169,10 @@ class ProfileListItem extends Widget
|
||||
$this->showBio();
|
||||
Event::handle('EndProfileListItemBio', array($this));
|
||||
}
|
||||
if (Event::handle('StartProfileListItemTags', array($this))) {
|
||||
$this->showTags();
|
||||
Event::handle('EndProfileListItemTags', array($this));
|
||||
}
|
||||
Event::handle('EndProfileListItemProfileElements', array($this));
|
||||
}
|
||||
$this->endProfile();
|
||||
@ -238,6 +243,20 @@ class ProfileListItem extends Widget
|
||||
}
|
||||
}
|
||||
|
||||
function showTags()
|
||||
{
|
||||
$user = common_current_user();
|
||||
if (!empty($user)) {
|
||||
if ($user->id == $this->profile->id) {
|
||||
$tags = new SelftagsWidget($this->out, $user, $this->profile);
|
||||
$tags->show();
|
||||
} else if ($user->getProfile()->canTag($this->profile)) {
|
||||
$tags = new PeopletagsWidget($this->out, $user, $this->profile);
|
||||
$tags->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function endProfile()
|
||||
{
|
||||
$this->out->elementEnd('div');
|
||||
|
@ -74,6 +74,10 @@ class PublicGroupNav extends Menu
|
||||
// TRANS: Menu item title in search group navigation panel.
|
||||
_('Recent tags'), $action_name == 'publictagcloud', 'nav_recent-tags');
|
||||
|
||||
$this->out->menuItem(common_local_url('publicpeopletagcloud'), _('People tags'),
|
||||
_('People tags'), in_array($action_name, array('publicpeopletagcloud',
|
||||
'peopletag', 'selftag')), 'nav_people-tags');
|
||||
|
||||
if (count(common_config('nickname', 'featured')) > 0) {
|
||||
// TRANS: Menu item in search group navigation panel.
|
||||
$this->out->menuItem(common_local_url('featured'), _m('MENU','Featured'),
|
||||
|
144
lib/router.php
144
lib/router.php
@ -228,7 +228,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'));
|
||||
@ -359,10 +361,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'));
|
||||
@ -774,6 +772,72 @@ class Router
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
// Lists (people tags)
|
||||
|
||||
$m->connect('api/lists/memberships.:format',
|
||||
array('action' => 'ApiListMemberships',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/lists/memberships.:format',
|
||||
array('action' => 'ApiListMemberships',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/lists/subscriptions.:format',
|
||||
array('action' => 'ApiListSubscriptions',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/lists/subscriptions.:format',
|
||||
array('action' => 'ApiListSubscriptions',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
$m->connect('api/lists.:format',
|
||||
array('action' => 'ApiLists',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/lists.:format',
|
||||
array('action' => 'ApiLists',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/lists/:id.:format',
|
||||
array('action' => 'ApiList',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/lists/:id/statuses.:format',
|
||||
array('action' => 'ApiTimelineList',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json|rss|atom)'));
|
||||
|
||||
$m->connect('api/:user/:list_id/members.:format',
|
||||
array('action' => 'ApiListMembers',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'list_id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/:list_id/subscribers.:format',
|
||||
array('action' => 'ApiListSubscribers',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'list_id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/:list_id/members/:id.:format',
|
||||
array('action' => 'ApiListMember',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'list_id' => '[a-zA-Z0-9]+',
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/:user/:list_id/subscribers/:id.:format',
|
||||
array('action' => 'ApiListSubscriber',
|
||||
'user' => '[a-zA-Z0-9]+',
|
||||
'list_id' => '[a-zA-Z0-9]+',
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
// Tags
|
||||
$m->connect('api/statusnet/tags/timeline/:tag.:format',
|
||||
array('action' => 'ApiTimelineTag',
|
||||
@ -908,6 +972,76 @@ class Router
|
||||
array('action' => 'subqueue'),
|
||||
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),
|
||||
|
@ -61,8 +61,15 @@ class Section extends Widget
|
||||
array('id' => $this->divId(),
|
||||
'class' => 'section'));
|
||||
|
||||
$link = $this->link();
|
||||
if (!empty($link)) {
|
||||
$this->out->elementStart('h2');
|
||||
$this->out->element('a', array('href' => $link), $this->title());
|
||||
$this->out->elementEnd('h2');
|
||||
} else {
|
||||
$this->out->element('h2', null,
|
||||
$this->title());
|
||||
}
|
||||
|
||||
$have_more = $this->showContent();
|
||||
|
||||
@ -88,6 +95,11 @@ class Section extends Widget
|
||||
return _('Untitled section');
|
||||
}
|
||||
|
||||
function link()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->out->element('p', null,
|
||||
|
@ -128,6 +128,15 @@ class SubGroupNav extends Menu
|
||||
$this->user->nickname),
|
||||
$action == 'usergroups',
|
||||
'nav_usergroups');
|
||||
$this->out->menuItem(common_local_url('peopletagsbyuser',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('People tags'),
|
||||
sprintf(_('People tags by %s'),
|
||||
$this->user->nickname),
|
||||
in_array($action, array('peopletagsbyuser', 'peopletagsforuser')),
|
||||
'nav_timeline_peopletags');
|
||||
|
||||
if (common_config('invite', 'enabled') && !is_null($cur) && $this->user->id === $cur->id) {
|
||||
$this->out->menuItem(common_local_url('invite'),
|
||||
// TRANS: Menu item in local navigation menu.
|
||||
|
114
lib/subscribepeopletagform.php
Normal file
114
lib/subscribepeopletagform.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for subscribing 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 Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for subscribing to a peopletag
|
||||
*
|
||||
* @category Form
|
||||
* @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/
|
||||
*
|
||||
* @see UnsubscribeForm
|
||||
*/
|
||||
|
||||
class SubscribePeopletagForm extends Form
|
||||
{
|
||||
/**
|
||||
* peopletag for the user to join
|
||||
*/
|
||||
|
||||
var $peopletag = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param peopletag $peopletag peopletag to subscribe to
|
||||
*/
|
||||
|
||||
function __construct($out=null, $peopletag=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->peopletag = $peopletag;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'peopletag-subscribe-' . $this->peopletag->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_peopletag_subscribe';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('subscribepeopletag',
|
||||
array('id' => $this->peopletag->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Subscribe'));
|
||||
}
|
||||
}
|
@ -50,7 +50,9 @@ class SubscribersPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
|
||||
|
||||
function query() {
|
||||
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged group by tag order by weight desc';
|
||||
return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||
|
||||
return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on profile_list.tag = profile_tag.tag and profile_list.tagger = profile_tag.tagger and profile_tag.tagger = subscriber where subscribed=%d and subscribed != subscriber and profile_tag.tagger = tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
|
||||
|
||||
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,6 @@ class SubscribersPeopleTagCloudSection extends SubPeopleTagCloudSection
|
||||
|
||||
function query() {
|
||||
// return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed group by tag order by weight desc';
|
||||
return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed and tag is not null group by tag order by weight desc';
|
||||
return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagged and subscribed=profile_tag.tagger and profile_tag.tagger = profile_list.tagger and profile_tag.tag = profile_list.tag where subscribed=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
|
||||
}
|
||||
}
|
||||
|
@ -92,37 +92,4 @@ class SubscriptionListItem extends ProfileListItem
|
||||
$user = common_current_user();
|
||||
return (!empty($user) && ($this->owner->id == $user->id));
|
||||
}
|
||||
|
||||
function showTags()
|
||||
{
|
||||
$tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
|
||||
|
||||
if ($this->isOwn()) {
|
||||
$this->out->element('a', array('href' => common_local_url('tagother',
|
||||
array('id' => $this->profile->id))),
|
||||
// TRANS: Description for link to "tag other users" in widget to show a list of profiles.
|
||||
_('Tags'));
|
||||
} else {
|
||||
// TRANS: Text widget to show a list of profiles with their tags.
|
||||
$this->out->text(_('Tags'));
|
||||
}
|
||||
if ($tags) {
|
||||
$this->out->elementStart('ul', 'tags xoxo entity_tags');
|
||||
foreach ($tags as $tag) {
|
||||
$this->out->elementStart('li');
|
||||
// Avoid space by using raw output.
|
||||
$pt = '<span class="mark_hash">#</span><a rel="tag" href="' .
|
||||
common_local_url($this->action->trimmed('action'),
|
||||
array('nickname' => $this->owner->nickname,
|
||||
'tag' => $tag)) .
|
||||
'">' . $tag . '</a>';
|
||||
$this->out->raw($pt);
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
} else {
|
||||
// TRANS: Text if there are no tags in widget to show a list of profiles by tag.
|
||||
$this->out->text(_('(None)'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,9 @@ class SubscriptionsPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
|
||||
|
||||
function query() {
|
||||
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscriber != subscribed and tagger = tagged group by tag order by weight desc';
|
||||
return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||
|
||||
return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on profile_tag.tagger = subscribed and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_tag.tagger where subscriber=%d and subscribed != subscriber and profile_tag.tagger = profile_tag.tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
|
||||
|
||||
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,6 @@ class SubscriptionsPeopleTagCloudSection extends SubPeopleTagCloudSection
|
||||
|
||||
function query() {
|
||||
// return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed group by tag order by weight desc';
|
||||
return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed and tag is not null group by tag order by weight desc';
|
||||
return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagger and subscribed=tagged and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_list.tagger where subscriber=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
|
||||
}
|
||||
}
|
||||
|
322
lib/togglepeopletag.php
Normal file
322
lib/togglepeopletag.php
Normal file
@ -0,0 +1,322 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for editing 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 Form
|
||||
* @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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for editing a peopletag
|
||||
*
|
||||
* @category Form
|
||||
* @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/
|
||||
*
|
||||
* @see GroupEditForm
|
||||
*/
|
||||
|
||||
class SearchProfileForm extends Form
|
||||
{
|
||||
var $peopletag;
|
||||
|
||||
function __construct($out, Profile_list $peopletag)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->peopletag = $peopletag;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_peopletag-add-' . $this->peopletag->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_peopletag_edit_user_search';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('profilecompletion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, sprintf(_('Search and list people')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$fields = array('fulltext' => 'Everything',
|
||||
'nickname' => 'Nickname',
|
||||
'fullname' => 'Fullname',
|
||||
'description' => 'Description',
|
||||
'location' => 'Location',
|
||||
'uri' => 'Uri (Remote users)');
|
||||
|
||||
|
||||
$this->out->hidden('peopletag_id', $this->peopletag->id);
|
||||
$this->out->input('q', null);
|
||||
$this->out->dropdown('field', _('Search in'), $fields,
|
||||
_('Choose a field to search'), false, 'fulltext');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Search'));
|
||||
}
|
||||
}
|
||||
|
||||
class UntagButton extends Form
|
||||
{
|
||||
var $profile;
|
||||
var $peopletag;
|
||||
|
||||
function __construct($out, Profile $profile, Profile_list $peopletag)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->profile = $profile;
|
||||
$this->peopletag = $peopletag;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_peopletag-' . $this->peopletag->id . '-remove-' . $this->profile->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_user_remove_peopletag';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('removepeopletag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, sprintf(_('Untag %s as %s'),
|
||||
$this->profile->nickname, $this->peopletag->tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->hidden('peopletag_id', $this->peopletag->id);
|
||||
$this->out->hidden('tagged', $this->profile->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Remove'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TagButton extends Form
|
||||
{
|
||||
var $profile;
|
||||
var $peopletag;
|
||||
|
||||
function __construct($out, Profile $profile, Profile_list $peopletag)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->profile = $profile;
|
||||
$this->peopletag = $peopletag;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_peopletag-' . $this->peopletag->id . '-add-' . $this->profile->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_user_add_peopletag';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('addpeopletag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, sprintf(_('Tag %s as %s'),
|
||||
$this->profile->nickname, $this->peopletag->tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
UntagButton::formData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Add'));
|
||||
}
|
||||
}
|
||||
|
||||
class TaggedProfileItem extends Widget
|
||||
{
|
||||
var $profile=null;
|
||||
|
||||
function __construct($out=null, $profile)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->profile = $profile;
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->out->elementStart('a', array('class' => 'url',
|
||||
'href' => $this->profile->profileurl,
|
||||
'title' => $this->profile->getBestName()));
|
||||
$avatar = $this->profile->getAvatar(AVATAR_MINI_SIZE);
|
||||
$this->out->element('img', array('src' => (($avatar) ? $avatar->displayUrl() :
|
||||
Avatar::defaultImage(AVATAR_MINI_SIZE)),
|
||||
'width' => AVATAR_MINI_SIZE,
|
||||
'height' => AVATAR_MINI_SIZE,
|
||||
'class' => 'avatar photo',
|
||||
'alt' => $this->profile->getBestName()));
|
||||
$this->out->element('span', 'fn nickname', $this->profile->nickname);
|
||||
$this->out->elementEnd('a');
|
||||
}
|
||||
}
|
114
lib/unsubscribepeopletagform.php
Normal file
114
lib/unsubscribepeopletagform.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for unsubscribing 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 Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for unsubscribing to a peopletag
|
||||
*
|
||||
* @category Form
|
||||
* @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/
|
||||
*
|
||||
* @see UnunsubscribeForm
|
||||
*/
|
||||
|
||||
class UnsubscribePeopletagForm extends Form
|
||||
{
|
||||
/**
|
||||
* peopletag for the user to join
|
||||
*/
|
||||
|
||||
var $peopletag = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param peopletag $peopletag peopletag to unsubscribe to
|
||||
*/
|
||||
|
||||
function __construct($out=null, $peopletag=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->peopletag = $peopletag;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'peopletag-unsubscribe-' . $this->peopletag->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_peopletag_unsubscribe';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('unsubscribepeopletag',
|
||||
array('id' => $this->peopletag->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Unsubscribe'));
|
||||
}
|
||||
}
|
10
lib/util.php
10
lib/util.php
@ -754,11 +754,12 @@ function common_find_mentions($text, $notice)
|
||||
foreach ($hmatches[1] as $hmatch) {
|
||||
|
||||
$tag = common_canonical_tag($hmatch[0]);
|
||||
$plist = Profile_list::getByTaggerAndTag($sender->id, $tag);
|
||||
if (!empty($plist) && !$plist->private) {
|
||||
$tagged = $sender->getTaggedSubscribers($tag);
|
||||
|
||||
$tagged = Profile_tag::getTagged($sender->id, $tag);
|
||||
|
||||
$url = common_local_url('subscriptions',
|
||||
array('nickname' => $sender->nickname,
|
||||
$url = common_local_url('showprofiletag',
|
||||
array('tagger' => $sender->nickname,
|
||||
'tag' => $tag));
|
||||
|
||||
$mentions[] = array('mentioned' => $tagged,
|
||||
@ -766,6 +767,7 @@ function common_find_mentions($text, $notice)
|
||||
'position' => $hmatch[1],
|
||||
'url' => $url);
|
||||
}
|
||||
}
|
||||
|
||||
Event::handle('EndFindMentions', array($sender, $text, &$mentions));
|
||||
}
|
||||
|
@ -56,14 +56,25 @@ class OStatusPlugin extends Plugin
|
||||
array('action' => 'ownerxrd'));
|
||||
$m->connect('main/ostatus',
|
||||
array('action' => 'ostatusinit'));
|
||||
$m->connect('main/ostatustag',
|
||||
array('action' => 'ostatustag'));
|
||||
$m->connect('main/ostatustag?nickname=:nickname',
|
||||
array('action' => 'ostatustag'), array('nickname' => '[A-Za-z0-9_-]+'));
|
||||
$m->connect('main/ostatus?nickname=:nickname',
|
||||
array('action' => 'ostatusinit'), array('nickname' => '[A-Za-z0-9_-]+'));
|
||||
$m->connect('main/ostatus?group=:group',
|
||||
array('action' => 'ostatusinit'), array('group' => '[A-Za-z0-9_-]+'));
|
||||
$m->connect('main/ostatus?peopletag=:peopletag&tagger=:tagger',
|
||||
array('action' => 'ostatusinit'), array('tagger' => '[A-Za-z0-9_-]+',
|
||||
'peopletag' => '[A-Za-z0-9_-]+'));
|
||||
|
||||
// Remote subscription actions
|
||||
$m->connect('main/ostatussub',
|
||||
array('action' => 'ostatussub'));
|
||||
$m->connect('main/ostatusgroup',
|
||||
array('action' => 'ostatusgroup'));
|
||||
$m->connect('main/ostatuspeopletag',
|
||||
array('action' => 'ostatuspeopletag'));
|
||||
|
||||
// PuSH actions
|
||||
$m->connect('main/push/hub', array('action' => 'pushhub'));
|
||||
@ -79,6 +90,9 @@ class OStatusPlugin extends Plugin
|
||||
$m->connect('main/salmon/group/:id',
|
||||
array('action' => 'groupsalmon'),
|
||||
array('id' => '[0-9]+'));
|
||||
$m->connect('main/salmon/peopletag/:id',
|
||||
array('action' => 'peopletagsalmon'),
|
||||
array('id' => '[0-9]+'));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -151,6 +165,10 @@ class OStatusPlugin extends Plugin
|
||||
$salmonAction = 'groupsalmon';
|
||||
$group = $feed->getGroup();
|
||||
$id = $group->id;
|
||||
} else if ($feed instanceof AtomListNoticeFeed) {
|
||||
$salmonAction = 'peopletagsalmon';
|
||||
$peopletag = $feed->getList();
|
||||
$id = $peopletag->id;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
@ -212,21 +230,7 @@ class OStatusPlugin extends Plugin
|
||||
*/
|
||||
function onStartProfileRemoteSubscribe($output, $profile)
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($cur)) {
|
||||
// Add an OStatus subscribe
|
||||
$output->elementStart('li', 'entity_subscribe');
|
||||
$url = common_local_url('ostatusinit',
|
||||
array('nickname' => $profile->nickname));
|
||||
$output->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
// TRANS: Link description for link to subscribe to a remote user.
|
||||
_m('Subscribe'));
|
||||
|
||||
$output->elementEnd('li');
|
||||
}
|
||||
|
||||
$this->onStartProfileListItemActionElements($output, $profile);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -235,18 +239,127 @@ class OStatusPlugin extends Plugin
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($cur)) {
|
||||
// Add an OStatus subscribe
|
||||
$output->elementStart('li', 'entity_subscribe');
|
||||
$profile = $peopletag->getTagger();
|
||||
$url = common_local_url('ostatusinit',
|
||||
array('group' => $group->nickname));
|
||||
$widget->out->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
// TRANS: Link description for link to join a remote group.
|
||||
_m('Join'));
|
||||
_m('Subscribe'));
|
||||
|
||||
$output->elementEnd('li');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartSubscribePeopletagForm($output, $peopletag)
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($cur)) {
|
||||
$output->elementStart('li', 'entity_subscribe');
|
||||
$profile = $peopletag->getTagger();
|
||||
$url = common_local_url('ostatusinit',
|
||||
array('tagger' => $profile->nickname, 'peopletag' => $peopletag->tag));
|
||||
$output->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
_m('Subscribe'));
|
||||
|
||||
$output->elementEnd('li');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartShowTagProfileForm($action, $profile)
|
||||
{
|
||||
$action->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_tag_user',
|
||||
'class' => 'form_settings',
|
||||
'name' => 'tagprofile',
|
||||
'action' => common_local_url('tagprofile', array('id' => @$profile->id))));
|
||||
|
||||
$action->elementStart('fieldset');
|
||||
$action->element('legend', null, _('Tag remote profile'));
|
||||
$action->hidden('token', common_session_token());
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$action->elementStart('ul', 'form_data');
|
||||
$action->elementStart('li');
|
||||
|
||||
$action->input('uri', _('Remote profile'), $action->trimmed('uri'),
|
||||
_('OStatus user\'s address, like nickname@example.com or http://example.net/nickname'));
|
||||
$action->elementEnd('li');
|
||||
$action->elementEnd('ul');
|
||||
$action->submit('fetch', _('Fetch'));
|
||||
$action->elementEnd('fieldset');
|
||||
$action->elementEnd('form');
|
||||
}
|
||||
|
||||
function onStartTagProfileAction($action, $profile)
|
||||
{
|
||||
$err = null;
|
||||
$uri = $action->trimmed('uri');
|
||||
|
||||
if (!$profile && $uri) {
|
||||
try {
|
||||
if (Validate::email($uri)) {
|
||||
$oprofile = Ostatus_profile::ensureWebfinger($uri);
|
||||
} else if (Validate::uri($uri)) {
|
||||
$oprofile = Ostatus_profile::ensureProfileURL($uri);
|
||||
} else {
|
||||
throw new Exception('Invalid URI');
|
||||
}
|
||||
|
||||
// redirect to the new profile.
|
||||
common_redirect(common_local_url('tagprofile', array('id' => $oprofile->profile_id)), 303);
|
||||
return false;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$err = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
||||
}
|
||||
|
||||
$action->showForm($err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the field being looked for is URI look for the profile
|
||||
*/
|
||||
function onStartProfileCompletionSearch($action, $profile, $search_engine) {
|
||||
if ($action->field == 'uri') {
|
||||
$user = new User();
|
||||
$profile->joinAdd($user);
|
||||
$profile->whereAdd('uri LIKE "%' . $profile->escape($q) . '%"');
|
||||
$profile->query();
|
||||
|
||||
if ($profile->N == 0) {
|
||||
try {
|
||||
if (Validate::email($q)) {
|
||||
$oprofile = Ostatus_profile::ensureWebfinger($q);
|
||||
} else if (Validate::uri($q)) {
|
||||
$oprofile = Ostatus_profile::ensureProfileURL($q);
|
||||
} else {
|
||||
throw new Exception('Invalid URI');
|
||||
}
|
||||
return $this->filter(array($oprofile->localProfile()));
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->msg = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
||||
return array();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find any explicit remote mentions. Accepted forms:
|
||||
* Webfinger: @user@example.com
|
||||
@ -713,6 +826,95 @@ class OStatusPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When one of our local users tries to subscribe to a remote peopletag,
|
||||
* notify the remote server. If the notification is rejected,
|
||||
* deny the subscription.
|
||||
*
|
||||
* @param Profile_list $peopletag
|
||||
* @param User $user
|
||||
*
|
||||
* @return mixed hook return value
|
||||
*/
|
||||
|
||||
function onStartSubscribePeopletag($peopletag, $user)
|
||||
{
|
||||
$oprofile = Ostatus_profile::staticGet('peopletag_id', $peopletag->id);
|
||||
if ($oprofile) {
|
||||
if (!$oprofile->subscribe()) {
|
||||
throw new Exception(_m('Could not set up remote peopletag subscription.'));
|
||||
}
|
||||
|
||||
$sub = $user->getProfile();
|
||||
$tagger = Profile::staticGet($peopletag->tagger);
|
||||
|
||||
$act = new Activity();
|
||||
$act->id = TagURI::mint('subscribe_peopletag:%d:%d:%s',
|
||||
$sub->id,
|
||||
$peopletag->id,
|
||||
common_date_iso8601(time()));
|
||||
|
||||
$act->actor = ActivityObject::fromProfile($sub);
|
||||
$act->verb = ActivityVerb::FOLLOW;
|
||||
$act->object = $oprofile->asActivityObject();
|
||||
|
||||
$act->time = time();
|
||||
$act->title = _m("Follow list");
|
||||
$act->content = sprintf(_m("%s is now following people tagged %s by %s."),
|
||||
$sub->getBestName(),
|
||||
$oprofile->getBestName(),
|
||||
$tagger->getBestName());
|
||||
|
||||
if ($oprofile->notifyActivity($act, $sub)) {
|
||||
return true;
|
||||
} else {
|
||||
$oprofile->garbageCollect();
|
||||
throw new Exception(_m("Failed subscribing to remote peopletag."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When one of our local users unsubscribes to a remote peopletag, notify the remote
|
||||
* server.
|
||||
*
|
||||
* @param Profile_list $peopletag
|
||||
* @param User $user
|
||||
*
|
||||
* @return mixed hook return value
|
||||
*/
|
||||
|
||||
function onEndUnsubscribePeopletag($peopletag, $user)
|
||||
{
|
||||
$oprofile = Ostatus_profile::staticGet('peopletag_id', $peopletag->id);
|
||||
if ($oprofile) {
|
||||
// Drop the PuSH subscription if there are no other subscribers.
|
||||
$oprofile->garbageCollect();
|
||||
|
||||
$sub = Profile::staticGet($user->id);
|
||||
$tagger = Profile::staticGet($peopletag->tagger);
|
||||
|
||||
$act = new Activity();
|
||||
$act->id = TagURI::mint('unsubscribe_peopletag:%d:%d:%s',
|
||||
$sub->id,
|
||||
$peopletag->id,
|
||||
common_date_iso8601(time()));
|
||||
|
||||
$act->actor = ActivityObject::fromProfile($member);
|
||||
$act->verb = ActivityVerb::UNFOLLOW;
|
||||
$act->object = $oprofile->asActivityObject();
|
||||
|
||||
$act->time = time();
|
||||
$act->title = _m("Unfollow peopletag");
|
||||
$act->content = sprintf(_m("%s stopped following the list %s by %s."),
|
||||
$sub->getBestName(),
|
||||
$oprofile->getBestName(),
|
||||
$tagger->getBestName());
|
||||
|
||||
$oprofile->notifyActivity($act, $user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify remote users when their notices get favorited.
|
||||
*
|
||||
@ -749,6 +951,108 @@ class OStatusPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify remote user it has got a new people tag
|
||||
* - tag verb is queued
|
||||
* - the subscription is done immediately if not present
|
||||
*
|
||||
* @param Profile_tag $ptag the people tag that was created
|
||||
* @return hook return value
|
||||
*/
|
||||
function onEndTagProfile($ptag)
|
||||
{
|
||||
$oprofile = Ostatus_profile::staticGet('profile_id', $ptag->tagged);
|
||||
|
||||
if (empty($oprofile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$plist = $ptag->getMeta();
|
||||
if ($plist->private) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$act = new Activity();
|
||||
|
||||
$tagger = $plist->getTagger();
|
||||
$tagged = Profile::staticGet('id', $ptag->tagged);
|
||||
|
||||
$act->verb = ActivityVerb::TAG;
|
||||
$act->id = TagURI::mint('tag_profile:%d:%d:%s',
|
||||
$plist->tagger, $plist->id,
|
||||
common_date_iso8601(time()));
|
||||
$act->time = time();
|
||||
$act->title = _("Tag");
|
||||
$act->content = sprintf(_("%s tagged %s in the list %s"),
|
||||
$tagger->getBestName(),
|
||||
$tagged->getBestName(),
|
||||
$plist->getBestName());
|
||||
|
||||
$act->actor = ActivityObject::fromProfile($tagger);
|
||||
$act->objects = array(ActivityObject::fromProfile($tagged));
|
||||
$act->target = ActivityObject::fromPeopletag($plist);
|
||||
|
||||
$oprofile->notifyDeferred($act, $tagger);
|
||||
|
||||
// initiate a PuSH subscription for the person being tagged
|
||||
if (!$oprofile->subscribe()) {
|
||||
throw new Exception(sprintf(_('Could not complete subscription to remote '.
|
||||
'profile\'s feed. Tag %s could not be saved.'), $ptag->tag));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify remote user that a people tag has been removed
|
||||
* - untag verb is queued
|
||||
* - the subscription is undone immediately if not required
|
||||
* i.e garbageCollect()'d
|
||||
*
|
||||
* @param Profile_tag $ptag the people tag that was deleted
|
||||
* @return hook return value
|
||||
*/
|
||||
function onEndUntagProfile($ptag)
|
||||
{
|
||||
$oprofile = Ostatus_profile::staticGet('profile_id', $ptag->tagged);
|
||||
|
||||
if (empty($oprofile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$plist = $ptag->getMeta();
|
||||
if ($plist->private) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$act = new Activity();
|
||||
|
||||
$tagger = $plist->getTagger();
|
||||
$tagged = Profile::staticGet('id', $ptag->tagged);
|
||||
|
||||
$act->verb = ActivityVerb::UNTAG;
|
||||
$act->id = TagURI::mint('untag_profile:%d:%d:%s',
|
||||
$plist->tagger, $plist->id,
|
||||
common_date_iso8601(time()));
|
||||
$act->time = time();
|
||||
$act->title = _("Untag");
|
||||
$act->content = sprintf(_("%s untagged %s from the list %s"),
|
||||
$tagger->getBestName(),
|
||||
$tagged->getBestName(),
|
||||
$plist->getBestName());
|
||||
|
||||
$act->actor = ActivityObject::fromProfile($tagger);
|
||||
$act->objects = array(ActivityObject::fromProfile($tagged));
|
||||
$act->target = ActivityObject::fromPeopletag($plist);
|
||||
|
||||
$oprofile->notifyDeferred($act, $tagger);
|
||||
|
||||
// unsubscribe to PuSH feed if no more required
|
||||
$oprofile->garbageCollect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify remote users when their notices get de-favorited.
|
||||
*
|
||||
@ -915,7 +1219,7 @@ class OStatusPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartProfileListItemActionElements($item)
|
||||
function onStartProfileListItemActionElements($item, $profile=null)
|
||||
{
|
||||
if (!common_logged_in()) {
|
||||
|
||||
@ -923,7 +1227,12 @@ class OStatusPlugin extends Plugin
|
||||
|
||||
if (!empty($profileUser)) {
|
||||
|
||||
if ($item instanceof Action) {
|
||||
$output = $item;
|
||||
$profile = $item->profile;
|
||||
} else {
|
||||
$output = $item->out;
|
||||
}
|
||||
|
||||
// Add an OStatus subscribe
|
||||
$output->elementStart('li', 'entity_subscribe');
|
||||
@ -934,6 +1243,14 @@ class OStatusPlugin extends Plugin
|
||||
// TRANS: Link text for a user to subscribe to an OStatus user.
|
||||
_m('Subscribe'));
|
||||
$output->elementEnd('li');
|
||||
|
||||
$output->elementStart('li', 'entity_tag');
|
||||
$url = common_local_url('ostatustag',
|
||||
array('nickname' => $profileUser->nickname));
|
||||
$output->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_tag'),
|
||||
_m('Tag'));
|
||||
$output->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,8 @@ if (!defined('STATUSNET')) {
|
||||
class OStatusInitAction extends Action
|
||||
{
|
||||
var $nickname;
|
||||
var $tagger;
|
||||
var $peopletag;
|
||||
var $group;
|
||||
var $profile;
|
||||
var $err;
|
||||
@ -45,6 +47,8 @@ class OStatusInitAction extends Action
|
||||
|
||||
// Local user or group the remote wants to subscribe to
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->tagger = $this->trimmed('tagger');
|
||||
$this->peopletag = $this->trimmed('peopletag');
|
||||
$this->group = $this->trimmed('group');
|
||||
|
||||
// Webfinger or profile URL of the remote user
|
||||
@ -96,8 +100,12 @@ class OStatusInitAction extends Action
|
||||
if ($this->group) {
|
||||
// TRANS: Form legend.
|
||||
$header = sprintf(_m('Join group %s'), $this->group);
|
||||
// TRANS: Button text.
|
||||
$submit = _m('BUTTON','Join');
|
||||
} else if ($this->peopletag && $this->tagger) {
|
||||
$header = sprintf(_m('Subscribe to people tagged %s by %s'), $this->peopletag, $this->tagger);
|
||||
$submit = _m('Subscribe');
|
||||
$submit = _m('BUTTON','Subscribe');
|
||||
// TRANS: Button text.
|
||||
} else {
|
||||
// TRANS: Form legend.
|
||||
$header = sprintf(_m('Subscribe to %s'), $this->nickname);
|
||||
@ -114,6 +122,7 @@ class OStatusInitAction extends Action
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li', array('id' => 'ostatus_nickname'));
|
||||
|
||||
if ($this->group) {
|
||||
// TRANS: Field label.
|
||||
$this->input('group', _m('Group nickname'), $this->group,
|
||||
@ -122,7 +131,10 @@ class OStatusInitAction extends Action
|
||||
// TRANS: Field label.
|
||||
$this->input('nickname', _m('User nickname'), $this->nickname,
|
||||
_m('Nickname of the user you want to follow.'));
|
||||
$this->hidden('tagger', $this->tagger);
|
||||
$this->hidden('peopletag', $this->peopletag);
|
||||
}
|
||||
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li', array('id' => 'ostatus_profile'));
|
||||
// TRANS: Field label.
|
||||
@ -211,6 +223,18 @@ class OStatusInitAction extends Action
|
||||
// TRANS: Client error.
|
||||
$this->clientError("No such group.");
|
||||
}
|
||||
} else if ($this->peopletag && $this->tagger) {
|
||||
$user = User::staticGet('nickname', $this->tagger);
|
||||
if (empty($user)) {
|
||||
$this->clientError("No such user.");
|
||||
}
|
||||
|
||||
$peopletag = Profile_list::getByTaggerAndTag($user->id, $this->peopletag);
|
||||
if ($peopletag) {
|
||||
return common_local_url('profiletagbyid',
|
||||
array('tagger_id' => $user->id, 'id' => $peopletag->id));
|
||||
}
|
||||
$this->clientError("No such people tag.");
|
||||
} else {
|
||||
// TRANS: Client error.
|
||||
$this->clientError("No local user or group nickname provided.");
|
||||
|
179
plugins/OStatus/actions/ostatuspeopletag.php
Normal file
179
plugins/OStatus/actions/ostatuspeopletag.php
Normal file
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2009-2010, 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @package OStatusPlugin
|
||||
* @maintainer Brion Vibber <brion@status.net>
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once INSTALLDIR . '/lib/peopletaglist.php';
|
||||
|
||||
/**
|
||||
* Key UI methods:
|
||||
*
|
||||
* showInputForm() - form asking for a remote profile account or URL
|
||||
* We end up back here on errors
|
||||
*
|
||||
* showPreviewForm() - surrounding form for preview-and-confirm
|
||||
* preview() - display profile for a remote group
|
||||
*
|
||||
* success() - redirects to groups page on join
|
||||
*/
|
||||
class OStatusPeopletagAction extends OStatusSubAction
|
||||
{
|
||||
protected $profile_uri; // provided acct: or URI of remote entity
|
||||
protected $oprofile; // Ostatus_profile of remote entity, if valid
|
||||
|
||||
|
||||
function validateRemoteProfile()
|
||||
{
|
||||
if (!$this->oprofile->isPeopletag()) {
|
||||
// Send us to the user subscription form for conf
|
||||
$target = common_local_url('ostatussub', array(), array('profile' => $this->profile_uri));
|
||||
common_redirect($target, 303);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the initial form, when we haven't yet been given a valid
|
||||
* remote profile.
|
||||
*/
|
||||
function showInputForm()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_ostatus_sub',
|
||||
'class' => 'form_settings',
|
||||
'action' => $this->selfLink()));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_feeds'));
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('profile',
|
||||
_m('Subscribe to people tag'),
|
||||
$this->profile_uri,
|
||||
_m("Address of the OStatus people tag, like http://example.net/user/all/tag"));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->submit('validate', _m('Continue'));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a preview for a remote peopletag's profile
|
||||
* @return boolean true if we're ok to try joining
|
||||
*/
|
||||
function preview()
|
||||
{
|
||||
$oprofile = $this->oprofile;
|
||||
$ptag = $oprofile->localPeopletag();
|
||||
|
||||
$cur = common_current_user();
|
||||
if ($ptag->hasSubscriber($cur->id)) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
_m("You are already subscribed to this peopletag."));
|
||||
$ok = false;
|
||||
} else {
|
||||
$ok = true;
|
||||
}
|
||||
|
||||
$this->showEntity($ptag);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
function showEntity($ptag)
|
||||
{
|
||||
$this->elementStart('div', 'peopletag');
|
||||
$widget = new PeopletagListItem($ptag, common_current_user(), $this);
|
||||
$widget->showCreator();
|
||||
$widget->showTag();
|
||||
$widget->showDescription();
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect on successful remote people tag subscription
|
||||
*/
|
||||
function success()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$url = common_local_url('peopletagsubscriptions', array('nickname' => $cur->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to finalize subscription.
|
||||
* validateFeed must have been run first.
|
||||
*
|
||||
* Calls showForm on failure or success on success.
|
||||
*/
|
||||
function saveFeed()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$ptag = $this->oprofile->localPeopletag();
|
||||
if ($ptag->hasSubscriber($user->id)) {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Already subscribed!'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Profile_tag_subscription::add($ptag, $user);
|
||||
$this->success();
|
||||
} catch (Exception $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title for OStatus remote people tag subscription form
|
||||
return _m('Confirm subscription to remote people tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _m('You can subscribe to people tags from other supported sites. Paste the tag\'s profile URI below:');
|
||||
}
|
||||
|
||||
function selfLink()
|
||||
{
|
||||
return common_local_url('ostatuspeopletag');
|
||||
}
|
||||
}
|
@ -270,10 +270,13 @@ class OStatusSubAction extends Action
|
||||
|
||||
function validateRemoteProfile()
|
||||
{
|
||||
// Send us to the respective subscription form for conf
|
||||
if ($this->oprofile->isGroup()) {
|
||||
// Send us to the group subscription form for conf
|
||||
$target = common_local_url('ostatusgroup', array(), array('profile' => $this->profile_uri));
|
||||
common_redirect($target, 303);
|
||||
} else if ($this->oprofile->isPeopletag()) {
|
||||
$target = common_local_url('ostatuspeopletag', array(), array('profile' => $this->profile_uri));
|
||||
common_redirect($target, 303);
|
||||
}
|
||||
}
|
||||
|
||||
|
117
plugins/OStatus/actions/ostatustag.php
Normal file
117
plugins/OStatus/actions/ostatustag.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @package OStatusPlugin
|
||||
* @maintainer James Walker <james@status.net>
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
|
||||
class OStatusTagAction extends OStatusInitAction
|
||||
{
|
||||
|
||||
var $nickname;
|
||||
var $profile;
|
||||
var $err;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (common_logged_in()) {
|
||||
$this->clientError(_m('You can use the local tagging!'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
|
||||
// Webfinger or profile URL of the remote user
|
||||
$this->profile = $this->trimmed('profile');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$header = sprintf(_m('Tag %s'), $this->nickname);
|
||||
$submit = _m('Go');
|
||||
$this->elementStart('form', array('id' => 'form_ostatus_connect',
|
||||
'method' => 'post',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('ostatustag')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, $header);
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li', array('id' => 'ostatus_nickname'));
|
||||
$this->input('nickname', _m('User nickname'), $this->nickname,
|
||||
_m('Nickname of the user you want to tag'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li', array('id' => 'ostatus_profile'));
|
||||
$this->input('profile', _m('Profile Account'), $this->profile,
|
||||
_m('Your account id (i.e. user@identi.ca)'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('submit', $submit);
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
function connectWebfinger($acct)
|
||||
{
|
||||
$target_profile = $this->targetProfile();
|
||||
|
||||
$disco = new Discovery;
|
||||
$result = $disco->lookup($acct);
|
||||
if (!$result) {
|
||||
$this->clientError(_m("Couldn't look up OStatus account profile."));
|
||||
}
|
||||
|
||||
foreach ($result->links as $link) {
|
||||
if ($link['rel'] == 'http://ostatus.org/schema/1.0/tag') {
|
||||
// We found a URL - let's redirect!
|
||||
$url = Discovery::applyTemplate($link['template'], $target_profile);
|
||||
common_log(LOG_INFO, "Sending remote subscriber $acct to $url");
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
}
|
||||
$this->clientError(_m("Couldn't confirm remote profile address."));
|
||||
}
|
||||
|
||||
function connectProfile($subscriber_profile)
|
||||
{
|
||||
$target_profile = $this->targetProfile();
|
||||
|
||||
// @fixme hack hack! We should look up the remote sub URL from XRDS
|
||||
$suburl = preg_replace('!^(.*)/(.*?)$!', '$1/main/tagprofile', $subscriber_profile);
|
||||
$suburl .= '?uri=' . urlencode($target_profile);
|
||||
|
||||
common_log(LOG_INFO, "Sending remote subscriber $subscriber_profile to $suburl");
|
||||
common_redirect($suburl, 303);
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _m('OStatus people tag');
|
||||
}
|
||||
}
|
141
plugins/OStatus/actions/peopletagsalmon.php
Normal file
141
plugins/OStatus/actions/peopletagsalmon.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @package OStatusPlugin
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class PeopletagsalmonAction extends SalmonAction
|
||||
{
|
||||
var $peopletag = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
|
||||
if (!$id) {
|
||||
$this->clientError(_('No ID.'));
|
||||
}
|
||||
|
||||
$this->peopletag = Profile_list::staticGet('id', $id);
|
||||
|
||||
if (empty($this->peopletag)) {
|
||||
$this->clientError(_('No such peopletag.'));
|
||||
}
|
||||
|
||||
$oprofile = Ostatus_profile::staticGet('peopletag_id', $id);
|
||||
|
||||
if (!empty($oprofile)) {
|
||||
$this->clientError(_m("Can't accept remote posts for a remote peopletag."));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* We've gotten a follow/subscribe notification from a remote user.
|
||||
* Save a subscription relationship for them.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Postel's law: consider a "follow" notification as a "join".
|
||||
*/
|
||||
function handleFollow()
|
||||
{
|
||||
$this->handleSubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Postel's law: consider an "unfollow" notification as a "unsubscribe".
|
||||
*/
|
||||
function handleUnfollow()
|
||||
{
|
||||
$this->handleUnsubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* A remote user subscribed.
|
||||
* @fixme move permission checks and event call into common code,
|
||||
* currently we're doing the main logic in joingroup action
|
||||
* and so have to repeat it here.
|
||||
*/
|
||||
|
||||
function handleSubscribe()
|
||||
{
|
||||
$oprofile = $this->ensureProfile();
|
||||
if (!$oprofile) {
|
||||
$this->clientError(_m("Can't read profile to set up profiletag subscription."));
|
||||
}
|
||||
if ($oprofile->isGroup()) {
|
||||
$this->clientError(_m("Groups can't subscribe to peopletags."));
|
||||
}
|
||||
|
||||
common_log(LOG_INFO, "Remote profile {$oprofile->uri} subscribing to local peopletag ".$this->peopletag->getBestName());
|
||||
$profile = $oprofile->localProfile();
|
||||
|
||||
if ($this->peopletag->hasSubscriber($profile)) {
|
||||
// Already a member; we'll take it silently to aid in resolving
|
||||
// inconsistencies on the other side.
|
||||
return true;
|
||||
}
|
||||
|
||||
// should we block those whom the tagger has blocked from listening to
|
||||
// his own updates?
|
||||
|
||||
try {
|
||||
Profile_tag_subscription::add($this->peopletag, $profile);
|
||||
} catch (Exception $e) {
|
||||
$this->serverError(sprintf(_m('Could not subscribe remote user %1$s to peopletag %2$s.'),
|
||||
$oprofile->uri, $this->peopletag->getBestName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A remote user unsubscribed from our peopletag.
|
||||
*/
|
||||
|
||||
function handleUnsubscribe()
|
||||
{
|
||||
$oprofile = $this->ensureProfile();
|
||||
if (!$oprofile) {
|
||||
$this->clientError(_m("Can't read profile to cancel peopletag membership."));
|
||||
}
|
||||
if ($oprofile->isGroup()) {
|
||||
$this->clientError(_m("Groups can't subscribe to peopletags."));
|
||||
}
|
||||
|
||||
common_log(LOG_INFO, "Remote profile {$oprofile->uri} unsubscribing from local peopletag ".$this->peopletag->getBestName());
|
||||
$profile = $oprofile->localProfile();
|
||||
|
||||
try {
|
||||
Profile_tag_subscription::remove($this->peopletag->tagger, $this->peopletag->tag, $profile->id);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->serverError(sprintf(_m('Could not remove remote user %1$s from peopletag %2$s.'),
|
||||
$oprofile->uri, $this->peopletag->getBestName()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -176,7 +176,22 @@ class PushHubAction extends Action
|
||||
return true;
|
||||
}
|
||||
}
|
||||
common_log(LOG_DEBUG, "Not a user or group feed? $feed $userFeed $groupFeed");
|
||||
} else if (preg_match('!/(\d+)/lists/(\d+)/statuses\.atom$!', $feed, $matches)) {
|
||||
$user = $matches[1];
|
||||
$id = $matches[2];
|
||||
$params = array('user' => $user, 'id' => $id, 'format' => 'atom');
|
||||
$listFeed = common_local_url('ApiTimelineList', $params);
|
||||
|
||||
if ($feed == $listFeed) {
|
||||
$list = Profile_list::staticGet('id', $id);
|
||||
$user = User::staticGet('id', $user);
|
||||
if (!$list || !$user || $list->tagger != $user->id) {
|
||||
throw new ClientException("Invalid hub.topic $feed; people tag doesn't exist.");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
common_log(LOG_DEBUG, "Not a user, group or people tag feed? $feed $userFeed $groupFeed $listFeed");
|
||||
}
|
||||
common_log(LOG_DEBUG, "LOST $feed");
|
||||
return false;
|
||||
|
@ -185,6 +185,67 @@ class UsersalmonAction extends SalmonAction
|
||||
$fave->delete();
|
||||
}
|
||||
|
||||
function handleTag()
|
||||
{
|
||||
if ($this->activity->target->type == ActivityObject::_LIST) {
|
||||
if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
|
||||
throw new ClientException("Not a person object");
|
||||
return false;
|
||||
}
|
||||
// this is a peopletag
|
||||
$tagged = User::staticGet('uri', $this->activity->objects[0]->id);
|
||||
|
||||
if (empty($tagged)) {
|
||||
throw new ClientException("Unidentified profile being tagged");
|
||||
}
|
||||
|
||||
if ($tagged->id !== $this->user->id) {
|
||||
throw new ClientException("This user is not the one being tagged");
|
||||
}
|
||||
|
||||
// save the list
|
||||
$tagger = $this->ensureProfile();
|
||||
$list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
|
||||
|
||||
$ptag = $list->localPeopletag();
|
||||
$result = Profile_tag::setTag($ptag->tagger, $tagged->id, $ptag->tag);
|
||||
if (!$result) {
|
||||
throw new ClientException("The tag could not be saved.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleUntag()
|
||||
{
|
||||
if ($this->activity->target->type == ActivityObject::_LIST) {
|
||||
if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
|
||||
throw new ClientException("Not a person object");
|
||||
return false;
|
||||
}
|
||||
// this is a peopletag
|
||||
$tagged = User::staticGet('uri', $this->activity->objects[0]->id);
|
||||
|
||||
if (empty($tagged)) {
|
||||
throw new ClientException("Unidentified profile being untagged");
|
||||
}
|
||||
|
||||
if ($tagged->id !== $this->user->id) {
|
||||
throw new ClientException("This user is not the one being untagged");
|
||||
}
|
||||
|
||||
// save the list
|
||||
$tagger = $this->ensureProfile();
|
||||
$list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
|
||||
|
||||
$ptag = $list->localPeopletag();
|
||||
$result = Profile_tag::unTag($ptag->tagger, $tagged->id, $ptag->tag);
|
||||
|
||||
if (!$result) {
|
||||
throw new ClientException("The tag could not be deleted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActivityObject $object
|
||||
* @return Notice
|
||||
|
@ -34,6 +34,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
|
||||
public $profile_id;
|
||||
public $group_id;
|
||||
public $peopletag_id;
|
||||
|
||||
public $feeduri;
|
||||
public $salmonuri;
|
||||
@ -60,6 +61,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
|
||||
'profile_id' => array('type' => 'integer'),
|
||||
'group_id' => array('type' => 'integer'),
|
||||
'peopletag_id' => array('type' => 'integer'),
|
||||
'feeduri' => array('type' => 'varchar', 'length' => 255),
|
||||
'salmonuri' => array('type' => 'varchar', 'length' => 255),
|
||||
'avatar' => array('type' => 'text'),
|
||||
@ -70,11 +72,13 @@ class Ostatus_profile extends Managed_DataObject
|
||||
'unique keys' => array(
|
||||
'ostatus_profile_profile_id_idx' => array('profile_id'),
|
||||
'ostatus_profile_group_id_idx' => array('group_id'),
|
||||
'ostatus_profile_peopletag_id_idx' => array('peopletag_id'),
|
||||
'ostatus_profile_feeduri_idx' => array('feeduri'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'ostatus_profile_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
|
||||
'ostatus_profile_group_id_fkey' => array('user_group', array('group_id' => 'id')),
|
||||
'ostatus_profile_peopletag_id_fkey' => array('profile_list', array('peopletag_id' => 'id')),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -103,6 +107,18 @@ class Ostatus_profile extends Managed_DataObject
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the StatusNet-side peopletag for this feed
|
||||
* @return Profile
|
||||
*/
|
||||
public function localPeopletag()
|
||||
{
|
||||
if ($this->peopletag_id) {
|
||||
return Profile_list::staticGet('id', $this->peopletag_id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ActivityObject describing this remote user or group profile.
|
||||
* Can then be used to generate Atom chunks.
|
||||
@ -113,6 +129,8 @@ class Ostatus_profile extends Managed_DataObject
|
||||
{
|
||||
if ($this->isGroup()) {
|
||||
return ActivityObject::fromGroup($this->localGroup());
|
||||
} else if ($this->isPeopletag()) {
|
||||
return ActivityObject::fromPeopletag($this->localPeopletag());
|
||||
} else {
|
||||
return ActivityObject::fromProfile($this->localProfile());
|
||||
}
|
||||
@ -134,6 +152,9 @@ class Ostatus_profile extends Managed_DataObject
|
||||
if ($this->isGroup()) {
|
||||
$noun = ActivityObject::fromGroup($this->localGroup());
|
||||
return $noun->asString('activity:' . $element);
|
||||
} else if ($this->isPeopletag()) {
|
||||
$noun = ActivityObject::fromPeopletag($this->localPeopletag());
|
||||
return $noun->asString('activity:' . $element);
|
||||
} else {
|
||||
$noun = ActivityObject::fromProfile($this->localProfile());
|
||||
return $noun->asString('activity:' . $element);
|
||||
@ -145,16 +166,34 @@ class Ostatus_profile extends Managed_DataObject
|
||||
*/
|
||||
function isGroup()
|
||||
{
|
||||
if ($this->profile_id && !$this->group_id) {
|
||||
if ($this->profile_id || $this->peopletag_id && !$this->group_id) {
|
||||
return false;
|
||||
} else if ($this->group_id && !$this->profile_id) {
|
||||
} else if ($this->group_id && !$this->profile_id && !$this->peopletag_id) {
|
||||
return true;
|
||||
} else if ($this->group_id && $this->profile_id) {
|
||||
// TRANS: Server exception. %s is a URI.
|
||||
throw new ServerException(sprintf(_m('Invalid ostatus_profile state: both group and profile IDs set for %s.'),$this->uri));
|
||||
} else if ($this->group_id && ($this->profile_id || $this->peopletag_id)) {
|
||||
// TRANS: Server exception. %s is a URI
|
||||
throw new ServerException(_m("Invalid ostatus_profile state: two or more IDs set for %s", $this->uri));
|
||||
} else {
|
||||
// TRANS: Server exception. %s is a URI.
|
||||
throw new ServerException(sprintf(_m('Invalid ostatus_profile state: both group and profile IDs empty for %s.'),$this->uri));
|
||||
// TRANS: Server exception. %s is a URI
|
||||
throw new ServerException(_m("Invalid ostatus_profile state: all IDs empty for %s", $this->uri));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean true if this is a remote peopletag
|
||||
*/
|
||||
function isPeopletag()
|
||||
{
|
||||
if ($this->profile_id || $this->group_id && !$this->peopletag_id) {
|
||||
return false;
|
||||
} else if ($this->peopletag_id && !$this->profile_id && !$this->group_id) {
|
||||
return true;
|
||||
} else if ($this->peopletag_id && ($this->profile_id || $this->group_id)) {
|
||||
// TRANS: Server exception. %s is a URI
|
||||
throw new ServerException(_m("Invalid ostatus_profile state: two or more IDs set for %s", $this->uri));
|
||||
} else {
|
||||
// TRANS: Server exception. %s is a URI
|
||||
throw new ServerException(_m("Invalid ostatus_profile state: all IDs empty for %s", $this->uri));
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,8 +253,15 @@ class Ostatus_profile extends Managed_DataObject
|
||||
if ($this->isGroup()) {
|
||||
$members = $this->localGroup()->getMembers(0, 1);
|
||||
$count = $members->N;
|
||||
} else if ($this->isPeopletag()) {
|
||||
$subscribers = $this->localPeopletag()->getSubscribers(0, 1);
|
||||
$count = $subscribers->N;
|
||||
} else {
|
||||
$count = $this->localProfile()->subscriberCount();
|
||||
$profile = $this->localProfile();
|
||||
$count = $profile->subscriberCount();
|
||||
if ($profile->hasLocalTags()) {
|
||||
$count = 1;
|
||||
}
|
||||
}
|
||||
common_log(LOG_INFO, __METHOD__ . " SUB COUNT BEFORE: $count");
|
||||
|
||||
@ -235,7 +281,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
* @param string $verb Activity::SUBSCRIBE or Activity::JOIN
|
||||
* @param Object $object object of the action; must define asActivityNoun($tag)
|
||||
*/
|
||||
public function notify($actor, $verb, $object=null)
|
||||
public function notify($actor, $verb, $object=null, $target=null)
|
||||
{
|
||||
if (!($actor instanceof Profile)) {
|
||||
$type = gettype($actor);
|
||||
@ -277,6 +323,9 @@ class Ostatus_profile extends Managed_DataObject
|
||||
$entry->raw($actor->asAtomAuthor());
|
||||
$entry->raw($actor->asActivityActor());
|
||||
$entry->raw($object->asActivityNoun('object'));
|
||||
if ($target != null) {
|
||||
$entry->raw($target->asActivityNoun('target'));
|
||||
}
|
||||
$entry->elementEnd('entry');
|
||||
|
||||
$xml = $entry->getString();
|
||||
@ -346,6 +395,8 @@ class Ostatus_profile extends Managed_DataObject
|
||||
{
|
||||
if ($this->isGroup()) {
|
||||
return $this->localGroup()->getBestName();
|
||||
} else if ($this->isPeopletag()) {
|
||||
return $this->localPeopletag()->getBestName();
|
||||
} else {
|
||||
return $this->localProfile()->getBestName();
|
||||
}
|
||||
@ -550,6 +601,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
'rendered' => $rendered,
|
||||
'replies' => array(),
|
||||
'groups' => array(),
|
||||
'peopletags' => array(),
|
||||
'tags' => array(),
|
||||
'urls' => array());
|
||||
|
||||
@ -586,6 +638,10 @@ class Ostatus_profile extends Managed_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isPeopletag()) {
|
||||
$options['peopletags'][] = $this->localPeopletag();
|
||||
}
|
||||
|
||||
// Atom categories <-> hashtags
|
||||
foreach ($activity->categories as $cat) {
|
||||
if ($cat->term) {
|
||||
@ -1202,6 +1258,14 @@ class Ostatus_profile extends Managed_DataObject
|
||||
throw new Exception(_m('Local group can\'t be referenced as remote.'));
|
||||
}
|
||||
|
||||
$ptag = Profile_list::staticGet('uri', $homeuri);
|
||||
if ($ptag) {
|
||||
$local_user = User::staticGet('id', $ptag->tagger);
|
||||
if (!empty($local_user)) {
|
||||
throw new Exception("Local peopletag can't be referenced as remote.");
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('feedurl', $hints)) {
|
||||
$feeduri = $hints['feedurl'];
|
||||
} else {
|
||||
@ -1253,7 +1317,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
// TRANS: Server exception.
|
||||
throw new ServerException(_m('Can\'t save local profile.'));
|
||||
}
|
||||
} else {
|
||||
} else if ($object->type == ActivityObject::GROUP) {
|
||||
$group = new User_group();
|
||||
$group->uri = $homeuri;
|
||||
$group->created = common_sql_now();
|
||||
@ -1264,6 +1328,16 @@ class Ostatus_profile extends Managed_DataObject
|
||||
// TRANS: Server exception.
|
||||
throw new ServerException(_m('Can\'t save local profile.'));
|
||||
}
|
||||
} else if ($object->type == ActivityObject::_LIST) {
|
||||
$ptag = new Profile_list();
|
||||
$ptag->uri = $homeuri;
|
||||
$ptag->created = common_sql_now();
|
||||
self::updatePeopletag($ptag, $object, $hints);
|
||||
|
||||
$oprofile->peopletag_id = $ptag->insert();
|
||||
if (!$oprofile->peopletag_id) {
|
||||
throw new ServerException("Can't save local peopletag");
|
||||
}
|
||||
}
|
||||
|
||||
$ok = $oprofile->insert();
|
||||
@ -1298,12 +1372,16 @@ class Ostatus_profile extends Managed_DataObject
|
||||
if ($this->isGroup()) {
|
||||
$group = $this->localGroup();
|
||||
self::updateGroup($group, $object, $hints);
|
||||
} else if ($this->isPeopletag()) {
|
||||
$ptag = $this->localPeopletag();
|
||||
self::updatePeopletag($ptag, $object, $hints);
|
||||
} else {
|
||||
$profile = $this->localProfile();
|
||||
self::updateProfile($profile, $object, $hints);
|
||||
}
|
||||
|
||||
$avatar = self::getActivityObjectAvatar($object, $hints);
|
||||
if ($avatar) {
|
||||
if ($avatar && !isset($ptag)) {
|
||||
try {
|
||||
$this->updateAvatar($avatar);
|
||||
} catch (Exception $ex) {
|
||||
@ -1401,6 +1479,27 @@ class Ostatus_profile extends Managed_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
protected static function updatePeopletag($tag, $object, $hints=array()) {
|
||||
$orig = clone($tag);
|
||||
|
||||
$tag->tag = $object->title;
|
||||
|
||||
if (!empty($object->link)) {
|
||||
$tag->mainpage = $object->link;
|
||||
} else if (array_key_exists('profileurl', $hints)) {
|
||||
$tag->mainpage = $hints['profileurl'];
|
||||
}
|
||||
|
||||
$tag->description = $object->summary;
|
||||
$tagger = self::ensureActivityObjectProfile($object->owner);
|
||||
$tag->tagger = $tagger->profile_id;
|
||||
|
||||
if ($tag->id) {
|
||||
common_log(LOG_DEBUG, "Updating OStatus peopletag $tag->id from remote info $object->id: " . var_export($object, true) . var_export($hints, true));
|
||||
$tag->update($orig);
|
||||
}
|
||||
}
|
||||
|
||||
protected static function getActivityObjectHomepage($object, $hints=array())
|
||||
{
|
||||
$homepage = null;
|
||||
@ -1781,15 +1880,14 @@ class Ostatus_profile extends Managed_DataObject
|
||||
|
||||
function checkAuthorship($activity)
|
||||
{
|
||||
if ($this->isGroup()) {
|
||||
// A group feed will contain posts from multiple authors.
|
||||
// @fixme validate these profiles in some way!
|
||||
if ($this->isGroup() || $this->isPeopletag()) {
|
||||
// A group or propletag feed will contain posts from multiple authors.
|
||||
$oprofile = self::ensureActorProfile($activity);
|
||||
if ($oprofile->isGroup()) {
|
||||
if ($oprofile->isGroup() || $oprofile->isPeopletag()) {
|
||||
// Groups can't post notices in StatusNet.
|
||||
common_log(LOG_WARNING,
|
||||
"OStatus: skipping post with group listed as author: ".
|
||||
"$oprofile->uri in feed from $this->uri");
|
||||
"OStatus: skipping post with group listed ".
|
||||
"as author: $oprofile->uri in feed from $this->uri");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -92,7 +92,8 @@ SN.U.DialogBox = {
|
||||
};
|
||||
|
||||
SN.Init.Subscribe = function() {
|
||||
$('.entity_subscribe .entity_remote_subscribe').live('click', function() { SN.U.DialogBox.Subscribe($(this)); return false; });
|
||||
$('.entity_subscribe .entity_remote_subscribe, .entity_tag .entity_remote_tag')
|
||||
.live('click', function() { SN.U.DialogBox.Subscribe($(this)); return false; });
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
|
@ -64,13 +64,6 @@ class OStatusQueueHandler extends QueueHandler
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($notice->getReplies() as $profile_id) {
|
||||
$oprofile = Ostatus_profile::staticGet('profile_id', $profile_id);
|
||||
if ($oprofile) {
|
||||
$this->pingReply($oprofile);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->notice->reply_to)) {
|
||||
$replyTo = Notice::staticGet('id', $this->notice->reply_to);
|
||||
if (!empty($replyTo)) {
|
||||
@ -82,6 +75,14 @@ class OStatusQueueHandler extends QueueHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($notice->getProfileTags() as $ptag) {
|
||||
$oprofile = Ostatus_profile::staticGet('peopletag_id', $ptag->id);
|
||||
if (!$oprofile) {
|
||||
$this->pushPeopletag($ptag);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -107,6 +108,17 @@ class OStatusQueueHandler extends QueueHandler
|
||||
$this->pushFeed($feed, array($this, 'groupFeedForNotice'), $group_id);
|
||||
}
|
||||
|
||||
function pushPeopletag($ptag)
|
||||
{
|
||||
// For a local people tag, ping the PuSH hub to update its feed.
|
||||
// Updates may come from either a local or a remote user.
|
||||
$feed = common_local_url('ApiTimelineList',
|
||||
array('id' => $ptag->id,
|
||||
'user' => $ptag->tagger,
|
||||
'format' => 'atom'));
|
||||
$this->pushFeed($feed, array($this, 'peopletagFeedForNotice'), $ptag);
|
||||
}
|
||||
|
||||
function pingReply($oprofile)
|
||||
{
|
||||
if ($this->user) {
|
||||
@ -225,4 +237,13 @@ class OStatusQueueHandler extends QueueHandler
|
||||
|
||||
return $feed;
|
||||
}
|
||||
|
||||
function peopletagFeedForNotice($ptag)
|
||||
{
|
||||
$atom = new AtomListNoticeFeed($ptag);
|
||||
$atom->addEntryFromNotice($this->notice);
|
||||
$feed = $atom->getString();
|
||||
|
||||
return $feed;
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,12 @@ class SalmonAction extends Action
|
||||
case ActivityVerb::LEAVE:
|
||||
$this->handleLeave();
|
||||
break;
|
||||
case ActivityVerb::TAG:
|
||||
$this->handleTag();
|
||||
break;
|
||||
case ActivityVerb::UNTAG:
|
||||
$this->handleUntag();
|
||||
break;
|
||||
case ActivityVerb::UPDATE_PROFILE:
|
||||
$this->handleUpdateProfile();
|
||||
break;
|
||||
@ -172,6 +178,16 @@ class SalmonAction extends Action
|
||||
throw new ClientException(_m("This target doesn't understand leave events."));
|
||||
}
|
||||
|
||||
function handleTag()
|
||||
{
|
||||
throw new ClientException(_m("This target doesn't understand tag events."));
|
||||
}
|
||||
|
||||
function handleUntag()
|
||||
{
|
||||
throw new ClientException(_m("This target doesn't understand untag events."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote user sent us an update to their profile.
|
||||
* If we already know them, accept the updates.
|
||||
|
131
plugins/OStatus/lib/xrdaction.php
Normal file
131
plugins/OStatus/lib/xrdaction.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @package OStatusPlugin
|
||||
* @maintainer James Walker <james@status.net>
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class XrdAction extends Action
|
||||
{
|
||||
public $uri;
|
||||
|
||||
public $user;
|
||||
|
||||
public $xrd;
|
||||
|
||||
function handle()
|
||||
{
|
||||
$nick = $this->user->nickname;
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if (empty($this->xrd)) {
|
||||
$xrd = new XRD();
|
||||
} else {
|
||||
$xrd = $this->xrd;
|
||||
}
|
||||
|
||||
if (empty($xrd->subject)) {
|
||||
$xrd->subject = Discovery::normalize($this->uri);
|
||||
}
|
||||
|
||||
// Possible aliases for the user
|
||||
|
||||
$uris = array($this->user->uri, $profile->profileurl);
|
||||
|
||||
// FIXME: Webfinger generation code should live somewhere on its own
|
||||
|
||||
$path = common_config('site', 'path');
|
||||
|
||||
if (empty($path)) {
|
||||
$uris[] = sprintf('acct:%s@%s', $nick, common_config('site', 'server'));
|
||||
}
|
||||
|
||||
foreach ($uris as $uri) {
|
||||
if ($uri != $xrd->subject) {
|
||||
$xrd->alias[] = $uri;
|
||||
}
|
||||
}
|
||||
|
||||
$xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
|
||||
'type' => 'text/html',
|
||||
'href' => $profile->profileurl);
|
||||
|
||||
$xrd->links[] = array('rel' => Discovery::UPDATESFROM,
|
||||
'href' => common_local_url('ApiTimelineUser',
|
||||
array('id' => $this->user->id,
|
||||
'format' => 'atom')),
|
||||
'type' => 'application/atom+xml');
|
||||
|
||||
// hCard
|
||||
$xrd->links[] = array('rel' => Discovery::HCARD,
|
||||
'type' => 'text/html',
|
||||
'href' => common_local_url('hcard', array('nickname' => $nick)));
|
||||
|
||||
// XFN
|
||||
$xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11',
|
||||
'type' => 'text/html',
|
||||
'href' => $profile->profileurl);
|
||||
// FOAF
|
||||
$xrd->links[] = array('rel' => 'describedby',
|
||||
'type' => 'application/rdf+xml',
|
||||
'href' => common_local_url('foaf',
|
||||
array('nickname' => $nick)));
|
||||
|
||||
// Salmon
|
||||
$salmon_url = common_local_url('usersalmon',
|
||||
array('id' => $this->user->id));
|
||||
|
||||
$xrd->links[] = array('rel' => Salmon::REL_SALMON,
|
||||
'href' => $salmon_url);
|
||||
// XXX : Deprecated - to be removed.
|
||||
$xrd->links[] = array('rel' => Salmon::NS_REPLIES,
|
||||
'href' => $salmon_url);
|
||||
|
||||
$xrd->links[] = array('rel' => Salmon::NS_MENTIONS,
|
||||
'href' => $salmon_url);
|
||||
|
||||
// Get this user's keypair
|
||||
$magickey = Magicsig::staticGet('user_id', $this->user->id);
|
||||
if (!$magickey) {
|
||||
// No keypair yet, let's generate one.
|
||||
$magickey = new Magicsig();
|
||||
$magickey->generate($this->user->id);
|
||||
}
|
||||
|
||||
$xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL,
|
||||
'href' => 'data:application/magic-public-key,'. $magickey->toString(false));
|
||||
|
||||
// TODO - finalize where the redirect should go on the publisher
|
||||
$url = common_local_url('ostatussub') . '?profile={uri}';
|
||||
$xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe',
|
||||
'template' => $url );
|
||||
|
||||
$url = common_local_url('tagprofile') . '?uri={uri}';
|
||||
$xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/tag',
|
||||
'template' => $url );
|
||||
|
||||
header('Content-type: application/xrd+xml');
|
||||
print $xrd->toXML();
|
||||
}
|
||||
}
|
@ -218,7 +218,7 @@ font-weight:bold;
|
||||
#form_settings_avatar legend,
|
||||
#newgroup legend,
|
||||
#editgroup legend,
|
||||
#form_tag_user legend,
|
||||
.form_tag_user legend,
|
||||
#form_remote_subscribe legend,
|
||||
#form_openid_login legend,
|
||||
#form_search legend,
|
||||
@ -228,10 +228,22 @@ font-weight:bold;
|
||||
#form_password_change legend,
|
||||
.form_entity_block legend,
|
||||
#form_filter_bytag legend,
|
||||
#apioauthauthorize_allowdeny {
|
||||
#apioauthauthorize_allowdeny,
|
||||
.form_tag_user_wrap form,
|
||||
.form_tag_user_wrap label,
|
||||
.form_tag_user_wrap legend {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.form_tag_user_wrap {
|
||||
clear:both;
|
||||
}
|
||||
.form_tag_user {
|
||||
float:left;
|
||||
width:auto;
|
||||
}
|
||||
.form_tag_user input.submit {
|
||||
width:50px;
|
||||
}
|
||||
.form_settings .form_data p.form_guide {
|
||||
clear:both;
|
||||
margin-left:26%;
|
||||
@ -709,7 +721,7 @@ min-height:123px;
|
||||
float:left;
|
||||
margin-bottom:18px;
|
||||
margin-left:0;
|
||||
overflow:hidden;
|
||||
overflow:visible;
|
||||
}
|
||||
.entity_profile dt,
|
||||
#entity_statistics dt {
|
||||
@ -737,6 +749,17 @@ margin-bottom:18px;
|
||||
margin-left:113px;
|
||||
margin-bottom:4px;
|
||||
}
|
||||
.entity_tags p.error {
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.peopletags_edit_button {
|
||||
cursor:pointer;
|
||||
border:0;
|
||||
padding:0;
|
||||
width:16px;
|
||||
height:16px;
|
||||
}
|
||||
|
||||
.entity_profile .entity_fn,
|
||||
.entity_profile .entity_nickname {
|
||||
@ -777,7 +800,6 @@ font-style:italic;
|
||||
.entity_actions {
|
||||
float:right;
|
||||
margin-left:2%;
|
||||
margin-bottom:18px;
|
||||
min-width:21%;
|
||||
}
|
||||
.entity_actions h2 {
|
||||
@ -966,13 +988,89 @@ min-height:60px;
|
||||
.profile .form_group_join legend,
|
||||
.profile .form_group_leave legend,
|
||||
.profile .form_user_subscribe legend,
|
||||
.profile .form_user_unsubscribe legend {
|
||||
.profile .form_user_unsubscribe legend,
|
||||
.form_user_add_peopletag legend,
|
||||
.form_user_remove_peopletag legend {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.profile_search_wrap h3 {
|
||||
float:left;
|
||||
font-weight:normal;
|
||||
margin-right:10px;
|
||||
}
|
||||
.profiles {
|
||||
list-style-type:none;
|
||||
}
|
||||
.peopletag .entry-content {
|
||||
width:auto;
|
||||
}
|
||||
.peopletag .tagged-count a:after,
|
||||
.peopletag .subscriber-count a:after {
|
||||
content: ':';
|
||||
}
|
||||
.peopletag .updated {
|
||||
display:none;
|
||||
}
|
||||
.peopletag .tag a{
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
.peopletag .tag:before {
|
||||
/* raquo */
|
||||
content: "\00BB";
|
||||
}
|
||||
.peopletag .entity_statistics {
|
||||
font-size:80%;
|
||||
}
|
||||
.peopletag .entity_statistics a {
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.profile-lister {
|
||||
list-style-type:none;
|
||||
}
|
||||
.profile-lister li {
|
||||
min-height:30px;
|
||||
padding:5px;
|
||||
clear:both;
|
||||
}
|
||||
.profile-lister li a {
|
||||
text-decoration:none;
|
||||
}
|
||||
.profile-lister li .photo {
|
||||
display:inline;
|
||||
margin-right:7px;
|
||||
margin-bottom:-5px;
|
||||
}
|
||||
.profile-lister li .fn {
|
||||
font-weight:bold;
|
||||
}
|
||||
#profile_search_results {
|
||||
border-radius:4px;
|
||||
-moz-border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
}
|
||||
.form_peopletag_edit_user_search legend,
|
||||
.form_peopletag_edit_user_search label,
|
||||
.form_peopletag_edit_user_search .form_guide {
|
||||
display:none;
|
||||
}
|
||||
.form_peopletag_edit_user_search #field {
|
||||
height:30px;
|
||||
}
|
||||
.form_peopletag_edit_user_search .submit {
|
||||
width:60px;
|
||||
}
|
||||
.form_user_remove_peopletag,
|
||||
.form_user_add_peopletag {
|
||||
float:right;
|
||||
}
|
||||
.form_user_add_peopletag input.submit,
|
||||
.form_user_remove_peopletag input.submit {
|
||||
width:100px;
|
||||
padding-left:25px;
|
||||
text-align:left;
|
||||
}
|
||||
.profile .entity_profile .fn.nickname,
|
||||
.profile .entity_profile .url[rel~=contact] {
|
||||
margin-left:0;
|
||||
@ -992,15 +1090,19 @@ clear:none;
|
||||
.profile .entity_profile .entity_tags,
|
||||
.profile .entity_profile .form_subscription_edit {
|
||||
margin-left:59px;
|
||||
margin-bottom:7px;
|
||||
clear:none;
|
||||
display:block;
|
||||
width:auto;
|
||||
}
|
||||
.profile .entity_profile .entity_tags dt {
|
||||
.entity_profile .entity_tags dt {
|
||||
display:inline;
|
||||
float:left;
|
||||
margin-right:11px;
|
||||
}
|
||||
|
||||
.profile .entity_profile .form_subscription_edit {
|
||||
clear:left;
|
||||
}
|
||||
.profile .entity_profile .form_subscription_edit label {
|
||||
font-weight:normal;
|
||||
margin-right:11px;
|
||||
@ -1085,7 +1187,8 @@ width:14.5%;
|
||||
/* NOTICE */
|
||||
.notice,
|
||||
.profile,
|
||||
.application {
|
||||
.application,
|
||||
#content .peopletag {
|
||||
position:relative;
|
||||
padding-top:11px;
|
||||
padding-bottom:11px;
|
||||
@ -1353,7 +1456,8 @@ margin-left:0;
|
||||
}
|
||||
.notice-options input,
|
||||
.notice-options a,
|
||||
.notice-options .repeated {
|
||||
.notice-options .repeated,
|
||||
.peopletags_edit_button {
|
||||
text-indent:-9999px;
|
||||
outline:none;
|
||||
}
|
||||
@ -1397,7 +1501,8 @@ height:16px;
|
||||
position:relative;
|
||||
padding-left:16px;
|
||||
}
|
||||
.notice .attachment.more {
|
||||
.notice .attachment.more,
|
||||
.mode-private .privacy_mode {
|
||||
text-indent:-9999px;
|
||||
width:16px;
|
||||
height:16px;
|
||||
@ -1510,16 +1615,22 @@ padding-left:7px;
|
||||
border-left-width:1px;
|
||||
border-left-style:solid;
|
||||
}
|
||||
#filter_tags #filter_tags_all {
|
||||
#filter_tags #filter_tags_all,
|
||||
#filter_tags #filter_tags_for {
|
||||
margin-left:0;
|
||||
border-left:0;
|
||||
padding-left:0;
|
||||
}
|
||||
#filter_tags_all a {
|
||||
#filter_tags_all a,
|
||||
#filter_tags_for a {
|
||||
text-decoration:none;
|
||||
font-weight:bold;
|
||||
margin-top:7px;
|
||||
float:left;
|
||||
}
|
||||
#filter_tags_for a {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#filter_tags_item label {
|
||||
margin-right:7px;
|
||||
@ -1538,6 +1649,15 @@ position:relative;
|
||||
top:3px;
|
||||
left:3px;
|
||||
}
|
||||
#filter_tags #form_filter_bymode .form_guide {
|
||||
display:none;
|
||||
}
|
||||
#filter_tags #form_filter_bymode .checkbox {
|
||||
float:none;
|
||||
}
|
||||
#filter_tags #form_filter_bymode legend {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
float:left;
|
||||
@ -1793,6 +1913,31 @@ width:auto;
|
||||
min-width:0;
|
||||
}
|
||||
|
||||
/* tag autocomplete */
|
||||
|
||||
.ptag-ac-line {
|
||||
font-weight: normal;
|
||||
background-color: white;
|
||||
}
|
||||
.ptag-ac-line:nth-child(odd) {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.ptag-ac-line-tag {
|
||||
min-width: 150px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ptag-ac-line .freq {
|
||||
min-width: 50px;
|
||||
text-align: right;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.ptag-ac-line.mode-public .privacy_mode {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.inline-attachment img {
|
||||
/* Why on earth is this changed to block at the top? */
|
||||
display: inline;
|
||||
|
@ -750,7 +750,7 @@ background-color:rgba(200, 200, 200, 0.300);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.entity_actions a, .entity_actions p, .entity_actions .entity_subscribe input, .entity_actions .entity_block input, .entity_actions .entity_moderation input, .entity_actions .entity_role input, .entity_actions .entity_nudge input, .entity_actions .entity_delete input {
|
||||
.entity_actions a, .entity_actions p, .entity_actions .entity_subscribe input, .entity_actions .entity_block input, .entity_actions .entity_moderation input, .entity_actions .entity_role input, .entity_actions .entity_nudge input, .entity_actions .entity_delete input, .entity_actions input.submit {
|
||||
text-shadow:0 1px 0 rgba(255,255,255,0.4);
|
||||
border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user