forked from GNUsocial/gnu-social
OStatus support for people tags
This commit is contained in:
parent
b372ed721d
commit
c335db4bbc
@ -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;
|
||||
}
|
||||
|
||||
@ -149,6 +163,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;
|
||||
}
|
||||
@ -210,21 +228,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;
|
||||
}
|
||||
|
||||
@ -238,13 +242,119 @@ class OStatusPlugin extends Plugin
|
||||
array('group' => $group->nickname));
|
||||
$output->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
// TRANS: Link description for link to join a remote group.
|
||||
_m('Join'));
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
@ -711,6 +821,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.
|
||||
*
|
||||
@ -747,6 +946,91 @@ class OStatusPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
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->notifyActivity($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;
|
||||
}
|
||||
|
||||
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->notifyActivity($act, $tagger);
|
||||
|
||||
// unsubscribe to PuSH feed if no more required
|
||||
$oprofile->garbageCollect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify remote users when their notices get de-favorited.
|
||||
*
|
||||
@ -913,7 +1197,7 @@ class OStatusPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartProfileListItemActionElements($item)
|
||||
function onStartProfileListItemActionElements($item, $profile=null)
|
||||
{
|
||||
if (!common_logged_in()) {
|
||||
|
||||
@ -921,7 +1205,12 @@ class OStatusPlugin extends Plugin
|
||||
|
||||
if (!empty($profileUser)) {
|
||||
|
||||
$output = $item->out;
|
||||
if ($item instanceof Action) {
|
||||
$output = $item;
|
||||
$profile = $item->profile;
|
||||
} else {
|
||||
$output = $item->out;
|
||||
}
|
||||
|
||||
// Add an OStatus subscribe
|
||||
$output->elementStart('li', 'entity_subscribe');
|
||||
@ -932,6 +1221,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");
|
||||
common_log(LOG_WARNING,
|
||||
"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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user