* Copyright (C) 2010, StatusNet, Inc.
*
* class to import activities as part of a user's timeline
- *
+ *
* PHP version 5
*
* This program is free software: you can redistribute it and/or modify
* @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);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Class comment
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
-
class ActivityImporter extends QueueHandler
{
private $trusted = false;
*
* @return
*/
-
function handle($data)
{
list($user, $author, $activity, $trusted) = $data;
$this->trusted = $trusted;
+ $done = null;
+
try {
- switch ($activity->verb) {
- case ActivityVerb::FOLLOW:
- $this->subscribeProfile($user, $author, $activity);
- break;
- case ActivityVerb::JOIN:
- $this->joinGroup($user, $activity);
- break;
- case ActivityVerb::POST:
- $this->postNote($user, $activity);
- break;
- default:
- throw new Exception("Unknown verb: {$activity->verb}");
+ if (Event::handle('StartImportActivity',
+ array($user, $author, $activity, $trusted, &$done))) {
+ switch ($activity->verb) {
+ case ActivityVerb::FOLLOW:
+ $this->subscribeProfile($user, $author, $activity);
+ break;
+ case ActivityVerb::JOIN:
+ $this->joinGroup($user, $activity);
+ break;
+ case ActivityVerb::POST:
+ $this->postNote($user, $author, $activity);
+ break;
+ default:
+ // TRANS: Client exception thrown when using an unknown verb for the activity importer.
+ throw new ClientException(sprintf(_("Unknown verb: \"%s\"."),$activity->verb));
+ }
+ Event::handle('EndImportActivity',
+ array($user, $author, $activity, $trusted));
+ $done = true;
}
- } catch (ClientException $ce) {
- common_log(LOG_WARNING, $ce->getMessage());
- return true;
- } catch (ServerException $se) {
- common_log(LOG_ERR, $se->getMessage());
- return false;
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
- return false;
+ $done = true;
}
- return true;
+ return $done;
}
-
+
function subscribeProfile($user, $author, $activity)
{
$profile = $user->getProfile();
if ($activity->objects[0]->id == $author->id) {
-
if (!$this->trusted) {
- throw new ClientException(_("Can't force subscription for untrusted user."));
+ // TRANS: Client exception thrown when trying to force a subscription for an untrusted user.
+ throw new ClientException(_('Cannot force subscription for untrusted user.'));
}
$other = $activity->actor;
- $otherUser = User::staticGet('uri', $other->id);
-
- if (!empty($otherUser)) {
- $otherProfile = $otherUser->getProfile();
- } else {
- throw new Exception("Can't force remote user to subscribe.");
+ $otherUser = User::getKV('uri', $other->id);
+
+ if (!$otherUser instanceof User) {
+ // TRANS: Client exception thrown when trying to force a remote user to subscribe.
+ throw new Exception(_('Cannot force remote user to subscribe.'));
}
- // XXX: don't do this for untrusted input!
+ $otherProfile = $otherUser->getProfile();
- Subscription::start($otherProfile, $profile);
+ // XXX: don't do this for untrusted input!
- } else if (empty($activity->actor)
+ Subscription::ensureStart($otherProfile, $profile);
+ } else if (empty($activity->actor)
|| $activity->actor->id == $author->id) {
$other = $activity->objects[0];
- $otherProfile = Profile::fromUri($other->id);
-
- if (empty($otherProfile)) {
- throw new ClientException(_("Unknown profile."));
+ try {
+ $otherProfile = Profile::fromUri($other->id);
+ // TRANS: Client exception thrown when trying to subscribe to an unknown profile.
+ } catch (UnknownUriException $e) {
+ // Let's convert it to a client exception instead of server.
+ throw new ClientException(_('Unknown profile.'));
}
- Subscription::start($profile, $otherProfile);
+ Subscription::ensureStart($profile, $otherProfile);
} else {
- throw new Exception("This activity seems unrelated to our user.");
+ // TRANS: Client exception thrown when trying to import an event not related to the importing user.
+ throw new Exception(_('This activity seems unrelated to our user.'));
}
}
$uri = $activity->objects[0]->id;
- $group = User_group::staticGet('uri', $uri);
+ $group = User_group::getKV('uri', $uri);
- if (empty($group)) {
+ if (!$group instanceof User_group) {
$oprofile = Ostatus_profile::ensureActivityObjectProfile($activity->objects[0]);
if (!$oprofile->isGroup()) {
- throw new Exception("Remote profile is not a group!");
+ // TRANS: Client exception thrown when trying to join a remote group that is not a group.
+ throw new ClientException(_('Remote profile is not a group!'));
}
$group = $oprofile->localGroup();
}
assert(!empty($group));
- if (Event::handle('StartJoinGroup', array($group, $user))) {
- Group_member::join($group->id, $user->id);
- Event::handle('EndJoinGroup', array($group, $user));
+ if ($user->isMember($group)) {
+ // TRANS: Client exception thrown when trying to join a group the importing user is already a member of.
+ throw new ClientException(_("User is already a member of this group."));
}
+
+ $user->joinGroup($group);
}
// XXX: largely cadged from Ostatus_profile::processNote()
- function postNote($user, $activity)
+ function postNote($user, $author, $activity)
{
$note = $activity->objects[0];
$sourceUri = $note->id;
- $notice = Notice::staticGet('uri', $sourceUri);
+ $notice = Notice::getKV('uri', $sourceUri);
- if (!empty($notice)) {
- // This is weird.
- $orig = clone($notice);
- $notice->profile_id = $user->id;
- $notice->update($orig);
- return;
+ if ($notice instanceof Notice) {
+
+ common_log(LOG_INFO, "Notice {$sourceUri} already exists.");
+
+ if ($this->trusted) {
+
+ $profile = $notice->getProfile();
+
+ $uri = $profile->getUri();
+
+ if ($uri === $author->id) {
+ common_log(LOG_INFO, sprintf('Updating notice author from %s to %s', $author->id, $user->getUri()));
+ $orig = clone($notice);
+ $notice->profile_id = $user->id;
+ $notice->update($orig);
+ return;
+ } else {
+ // TRANS: Client exception thrown when trying to import a notice by another user.
+ // TRANS: %1$s is the source URI of the notice, %2$s is the URI of the author.
+ throw new ClientException(sprintf(_('Already know about notice %1$s and '.
+ ' it has a different author %2$s.'),
+ $sourceUri, $uri));
+ }
+ } else {
+ // TRANS: Client exception thrown when trying to overwrite the author information for a non-trusted user during import.
+ throw new ClientException(_('Not overwriting author info for non-trusted user.'));
+ }
}
// Use summary as fallback for content
$sourceContent = $note->title;
} else {
// @fixme fetch from $sourceUrl?
- // @todo i18n FIXME: use sprintf and add i18n.
- throw new ClientException("No content for notice {$sourceUri}.");
+ // TRANS: Client exception thrown when trying to import a notice without content.
+ // TRANS: %s is the notice URI.
+ throw new ClientException(sprintf(_('No content for notice %s.'),$sourceUri));
}
// Get (safe!) HTML and text versions of the content
- $rendered = $this->purify($sourceContent);
- $content = html_entity_decode(strip_tags($rendered), ENT_QUOTES, 'UTF-8');
+ $rendered = common_purify($sourceContent);
+ $content = common_strip_html($rendered);
$shortened = $user->shortenLinks($content);
'replies' => array(),
'groups' => array(),
'tags' => array(),
- 'urls' => array());
+ 'urls' => array(),
+ 'distribute' => false);
// Check for optional attributes...
// Maintain direct reply associations
// @fixme what about conversation ID?
if (!empty($activity->context->replyToID)) {
- $orig = Notice::staticGet('uri',
- $activity->context->replyToID);
- if (!empty($orig)) {
+ $orig = Notice::getKV('uri', $activity->context->replyToID);
+ if ($orig instanceof Notice) {
$options['reply_to'] = $orig->id;
}
}
$options['urls'][] = $href;
}
+ common_log(LOG_INFO, "Saving notice {$options['uri']}");
+
$saved = Notice::saveNew($user->id,
$content,
'restore', // TODO: restore the actual source
return $saved;
}
- function filterAttention($attn)
+ protected function filterAttention(array $attn)
{
- $groups = array();
- $replies = array();
+ $groups = array(); // TODO: context->attention
+ $replies = array(); // TODO: context->attention
- foreach (array_unique($attn) as $recipient) {
+ foreach ($attn as $recipient=>$type) {
// Is the recipient a local user?
- $user = User::staticGet('uri', $recipient);
+ $user = User::getKV('uri', $recipient);
- if ($user) {
- // @fixme sender verification, spam etc?
+ if ($user instanceof User) {
+ // TODO: @fixme sender verification, spam etc?
$replies[] = $recipient;
continue;
}
}
// Is the recipient a local group?
- // @fixme uri on user_group isn't reliable yet
- // $group = User_group::staticGet('uri', $recipient);
+ // TODO: @fixme uri on user_group isn't reliable yet
+ // $group = User_group::getKV('uri', $recipient);
$id = OStatusPlugin::localGroupFromUrl($recipient);
if ($id) {
- $group = User_group::staticGet('id', $id);
+ $group = User_group::getKV('id', $id);
if ($group) {
// Deliver to all members of this local group if allowed.
$profile = $sender->localProfile();
return array($groups, $replies);
}
-
-
- function purify($content)
- {
- $config = array('safe' => 1,
- 'deny_attribute' => 'id,style,on*');
- return htmLawed($content, $config);
- }
}