X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FOStatus%2FOStatusPlugin.php;h=7c6c0c69f300b49b1794136333c9bc63e817dd9a;hb=3ed379613598645f75a402baa2c4abcf78984639;hp=e84d68504313faf384fdbedc43e26b68a7be0155;hpb=1cb94e0be63f16d85bb5e9c4a8f6791caf91c8c5;p=quix0rs-gnu-social.git diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index e84d685043..7c6c0c69f3 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -1,17 +1,7 @@ -Author URI: http://status.net/ -*/ - /* * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2009, StatusNet, Inc. + * 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 @@ -28,16 +18,13 @@ Author URI: http://status.net/ */ /** - * @package FeedSubPlugin + * @package OStatusPlugin * @maintainer Brion Vibber */ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -define('FEEDSUB_SERVICE', 100); // fixme -- avoid hardcoding these? - -// We bundle the XML_Parse_Feed library... -set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib'); +set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/'); class FeedSubException extends Exception { @@ -73,15 +60,13 @@ class OStatusPlugin extends Plugin $m->connect('main/push/callback/:feed', array('action' => 'pushcallback'), array('feed' => '[0-9]+')); - $m->connect('settings/feedsub', - array('action' => 'feedsubsettings')); // Salmon endpoint $m->connect('main/salmon/user/:id', - array('action' => 'salmon'), + array('action' => 'usersalmon'), array('id' => '[0-9]+')); $m->connect('main/salmon/group/:id', - array('action' => 'salmongroup'), + array('action' => 'groupsalmon'), array('id' => '[0-9]+')); return true; } @@ -93,9 +78,13 @@ class OStatusPlugin extends Plugin */ function onEndInitializeQueueManager(QueueManager $qm) { + // Outgoing from our internal PuSH hub $qm->connect('hubverify', 'HubVerifyQueueHandler'); $qm->connect('hubdistrib', 'HubDistribQueueHandler'); $qm->connect('hubout', 'HubOutQueueHandler'); + + // Incoming from a foreign PuSH hub + $qm->connect('pushinput', 'PushInputQueueHandler'); return true; } @@ -112,21 +101,26 @@ class OStatusPlugin extends Plugin * Set up a PuSH hub link to our internal link for canonical timeline * Atom feeds for users and groups. */ - function onStartApiAtom(AtomNoticeFeed $feed) + function onStartApiAtom($feed) { $id = null; if ($feed instanceof AtomUserNoticeFeed) { - $salmonAction = 'salmon'; - $id = $feed->getUser()->id; + $salmonAction = 'usersalmon'; + $user = $feed->getUser(); + $id = $user->id; + $profile = $user->getProfile(); + $feed->setActivitySubject($profile->asActivityNoun('subject')); } else if ($feed instanceof AtomGroupNoticeFeed) { - $salmonAction = 'salmongroup'; - $id = $feed->getGroup()->id; + $salmonAction = 'groupsalmon'; + $group = $feed->getGroup(); + $id = $group->id; + $feed->setActivitySubject($group->asActivitySubject()); } else { - return; + return true; } - if (!empty($id)) { + if (!empty($id)) { $hub = common_config('ostatus', 'hub'); if (empty($hub)) { // Updates will be handled through our internal PuSH hub. @@ -138,23 +132,6 @@ class OStatusPlugin extends Plugin $salmon = common_local_url($salmonAction, array('id' => $id)); $feed->addLink($salmon, array('rel' => 'salmon')); } - } - - /** - * Add the feed settings page to the Connect Settings menu - * - * @param Action &$action The calling page - * - * @return boolean hook return - */ - function onEndConnectSettingsNav(&$action) - { - $action_name = $action->trimmed('action'); - - $action->menuItem(common_local_url('feedsubsettings'), - _m('Feeds'), - _m('Feed subscription options'), - $action_name === 'feedsubsettings'); return true; } @@ -171,6 +148,12 @@ class OStatusPlugin extends Plugin { $base = dirname(__FILE__); $lower = strtolower($cls); + $map = array('activityverb' => 'activity', + 'activityobject' => 'activity', + 'activityutils' => 'activity'); + if (isset($map[$lower])) { + $lower = $map[$lower]; + } $files = array("$base/classes/$cls.php", "$base/lib/$lower.php"); if (substr($lower, -6) == 'action') { @@ -213,55 +196,110 @@ class OStatusPlugin extends Plugin * @fixme push webfinger lookup & sending to a background queue * @fixme also detect short-form name for remote subscribees where not ambiguous */ + function onEndNoticeSave($notice) { - $count = preg_match_all('/(\w+\.)*\w+@(\w+\.)*\w+(\w+\-\w+)*\.\w+/', $notice->content, $matches); - if ($count) { - foreach ($matches[0] as $webfinger) { - // Check to see if we've got an actual webfinger - $w = new Webfinger; + $mentioned = $notice->getReplies(); - $endpoint_uri = ''; + foreach ($mentioned as $profile_id) { - $result = $w->lookup($webfinger); - if (empty($result)) { - continue; - } + $oprofile = Ostatus_profile::staticGet('profile_id', $profile_id); - foreach ($result->links as $link) { - if ($link['rel'] == 'salmon') { - $endpoint_uri = $link['href']; - } - } + if (!empty($oprofile) && !empty($oprofile->salmonuri)) { - if (empty($endpoint_uri)) { - continue; - } + common_log(LOG_INFO, "Sending notice '{$notice->uri}' to remote profile '{$oprofile->uri}'."); + + // FIXME: this needs to go out in a queue handler $xml = ''; - $xml .= $notice->asAtomEntry(); + $xml .= $notice->asAtomEntry(true, true); $salmon = new Salmon(); - $salmon->post($endpoint_uri, $xml); + $salmon->post($oprofile->salmonuri, $xml); } } } /** - * Garbage collect unused feeds on unsubscribe + * */ - function onEndUnsubscribe($user, $other) + + function onEndFindMentions($sender, $text, &$mentions) { - $profile = Ostatus_profile::staticGet('profile_id', $other->id); - if ($feed) { - $sub = new Subscription(); - $sub->subscribed = $other->id; - $sub->limit(1); - if (!$sub->find(true)) { - common_log(LOG_INFO, "Unsubscribing from now-unused feed $feed->feeduri on hub $feed->huburi"); - $profile->unsubscribe(); + preg_match_all('/(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)/', + $text, + $wmatches, + PREG_OFFSET_CAPTURE); + + foreach ($wmatches[1] as $wmatch) { + + $webfinger = $wmatch[0]; + + $oprofile = Ostatus_profile::ensureWebfinger($webfinger); + + if (!empty($oprofile)) { + + $profile = $oprofile->localProfile(); + + $mentions[] = array('mentioned' => array($profile), + 'text' => $wmatch[0], + 'position' => $wmatch[1], + 'url' => $profile->profileurl); } } + + return true; + } + + /** + * Notify remote server and garbage collect unused feeds on unsubscribe. + * @fixme send these operations to background queues + * + * @param User $user + * @param Profile $other + * @return hook return value + */ + function onEndUnsubscribe($profile, $other) + { + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + // Drop the PuSH subscription if there are no other subscribers. + + if ($other->subscriberCount() == 0) { + common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri"); + $oprofile->unsubscribe(); + } + + $act = new Activity(); + + $act->verb = ActivityVerb::UNFOLLOW; + + $act->id = TagURI::mint('unfollow:%d:%d:%s', + $profile->id, + $other->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Unfollow"); + $act->content = sprintf(_("%s stopped following %s."), + $profile->getBestName(), + $other->getBestName()); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = ActivityObject::fromProfile($other); + + $oprofile->notifyActivity($act); + return true; } @@ -271,6 +309,8 @@ class OStatusPlugin extends Plugin function onCheckSchema() { $schema = Schema::get(); $schema->ensureTable('ostatus_profile', Ostatus_profile::schemaDef()); + $schema->ensureTable('ostatus_source', Ostatus_source::schemaDef()); + $schema->ensureTable('feedsub', FeedSub::schemaDef()); $schema->ensureTable('hubsub', HubSub::schemaDef()); return true; } @@ -279,4 +319,201 @@ class OStatusPlugin extends Plugin $action->cssLink(common_path('plugins/OStatus/theme/base/css/ostatus.css')); return true; } + + function onEndShowStatusNetScripts($action) { + $action->script(common_path('plugins/OStatus/js/ostatus.js')); + return true; + } + + /** + * Override the "from ostatus" bit in notice lists to link to the + * original post and show the domain it came from. + * + * @param Notice in $notice + * @param string out &$name + * @param string out &$url + * @param string out &$title + * @return mixed hook return code + */ + function onStartNoticeSourceLink($notice, &$name, &$url, &$title) + { + if ($notice->source == 'ostatus') { + $bits = parse_url($notice->uri); + $domain = $bits['host']; + + $name = $domain; + $url = $notice->uri; + $title = sprintf(_m("Sent from %s via OStatus"), $domain); + return false; + } + } + + /** + * Send incoming PuSH feeds for OStatus endpoints in for processing. + * + * @param FeedSub $feedsub + * @param DOMDocument $feed + * @return mixed hook return code + */ + function onStartFeedSubReceive($feedsub, $feed) + { + $oprofile = Ostatus_profile::staticGet('feeduri', $feedsub->uri); + if ($oprofile) { + $oprofile->processFeed($feed); + } else { + common_log(LOG_DEBUG, "No ostatus profile for incoming feed $feedsub->uri"); + } + } + + function onEndSubscribe($subscriber, $other) + { + $user = User::staticGet('id', $subscriber->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); + + if (empty($oprofile)) { + return true; + } + + $act = new Activity(); + + $act->verb = ActivityVerb::FOLLOW; + + $act->id = TagURI::mint('follow:%d:%d:%s', + $subscriber->id, + $other->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Follow"); + $act->content = sprintf(_("%s is now following %s."), + $subscriber->getBestName(), + $other->getBestName()); + + $act->actor = ActivityObject::fromProfile($subscriber); + $act->object = ActivityObject::fromProfile($other); + + $oprofile->notifyActivity($act); + + return true; + } + + /** + * Notify remote users when their notices get favorited. + * + * @param Profile or User $profile of local user doing the faving + * @param Notice $notice being favored + * @return hook return value + */ + + function onEndFavorNotice(Profile $profile, Notice $notice) + { + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + + if (empty($oprofile)) { + return true; + } + + $act = new Activity(); + + $act->verb = ActivityVerb::FAVORITE; + $act->id = TagURI::mint('favor:%d:%d:%s', + $profile->id, + $notice->id, + common_date_iso8601(time())); + + $act->time = time(); + $act->title = _("Favor"); + $act->content = sprintf(_("%s marked notice %s as a favorite."), + $profile->getBestName(), + $notice->uri); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = ActivityObject::fromNotice($notice); + + $oprofile->notifyActivity($act); + + return true; + } + + /** + * Notify remote users when their notices get de-favorited. + * + * @param Profile $profile Profile person doing the de-faving + * @param Notice $notice Notice being favored + * + * @return hook return value + */ + + function onEndDisfavorNotice(Profile $profile, Notice $notice) + { + $user = User::staticGet('id', $profile->id); + + if (empty($user)) { + return true; + } + + $oprofile = Ostatus_profile::staticGet('profile_id', $notice->profile_id); + + if (empty($oprofile)) { + return true; + } + + $act = new Activity(); + + $act->verb = ActivityVerb::UNFAVORITE; + $act->id = TagURI::mint('disfavor:%d:%d:%s', + $profile->id, + $notice->id, + common_date_iso8601(time())); + $act->time = time(); + $act->title = _("Disfavor"); + $act->content = sprintf(_("%s marked notice %s as no longer a favorite."), + $profile->getBestName(), + $notice->uri); + + $act->actor = ActivityObject::fromProfile($profile); + $act->object = ActivityObject::fromNotice($notice); + + $oprofile->notifyActivity($act); + + return true; + } + + function onStartGetProfileUri($profile, &$uri) + { + $oprofile = Ostatus_profile::staticGet('profile_id', $profile->id); + if (!empty($oprofile)) { + $uri = $oprofile->uri; + return false; + } + return true; + } + + function onStartShowSubscriptionsContent($action) + { + $user = common_current_user(); + if ($user && ($user->id == $action->profile->id)) { + $action->elementStart('div', 'entity_actions'); + $action->elementStart('p', array('id' => 'entity_remote_subscribe', + 'class' => 'entity_subscribe')); + $action->element('a', array('href' => common_local_url('ostatussub'), + 'class' => 'entity_remote_subscribe') + , _m('Subscribe to remote user')); + $action->elementEnd('p'); + $action->elementEnd('div'); + } + + return true; + } }