* @category Plugin
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
* @copyright 2009 StatusNet, Inc.
+ * @copyright 2014 Free Software Foundation, 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);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Superclass for plugin to do realtime updates
* Based on experience with the Comet and Meteor plugins,
* this superclass extracts out some of the common functionality
*
+ * Currently depends on Favorite plugin.
+ *
* @category Plugin
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* When it's time to initialize the plugin, calculate and
* pass the URLs we need.
*/
-
function onInitializePlugin()
{
// FIXME: need to find a better way to pass this pattern in
array('notice' => '0000000000'));
return true;
}
-
+
function onCheckSchema()
{
$schema = Schema::get();
$schema->ensureTable('realtime_channel', Realtime_channel::schemaDef());
return true;
}
-
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'KeepalivechannelAction':
- case 'ClosechannelAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Realtime_channel':
- include_once $dir.'/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
/**
* Hook for RouterInitialized event.
*
- * @param Net_URL_Mapper $m path-to-action mapper
+ * @param URLMapper $m path-to-action mapper
* @return boolean hook return
*/
- function onRouterInitialized($m)
+ public function onRouterInitialized(URLMapper $m)
{
$m->connect('main/channel/:channelkey/keepalive',
array('action' => 'keepalivechannel'),
$pluginPath = common_path('plugins/Realtime/');
$keepalive = common_local_url('keepalivechannel', array('channelkey' => $channel->channel_key));
$close = common_local_url('closechannel', array('channelkey' => $channel->channel_key));
- $realtimeUI = ' RealtimeUpdate.initActions("'.$url.'", "'.$timeline.'", "'. $pluginPath .'", "'.$keepalive.'", "'.$close.'"); ';
+ $realtimeUI = ' RealtimeUpdate.initActions('.json_encode($url).', '.json_encode($timeline).', '.json_encode($pluginPath).', '.json_encode($keepalive).', '.json_encode($close).'); ';
}
$script = ' $(document).ready(function() { '.
return true;
}
- function onEndShowStatusNetStyles($action)
+ public function onEndShowStylesheets(Action $action)
{
- $action->cssLink(Plugin::staticPath('Realtime', 'realtimeupdate.css'),
- null,
- 'screen, projection, tv');
+ $urlpath = self::staticPath(str_replace('Plugin','',__CLASS__),
+ 'css/realtimeupdate.css');
+ $action->cssLink($urlpath, null, 'screen, projection, tv');
return true;
}
- function onHandleQueuedNotice($notice)
+ public function onHandleQueuedNotice(Notice $notice)
{
$paths = array();
// Add to the author's timeline
- $user = User::staticGet('id', $notice->profile_id);
+ try {
+ $profile = $notice->getProfile();
+ } catch (Exception $e) {
+ $this->log(LOG_ERR, $e->getMessage());
+ return true;
+ }
- if (!empty($user)) {
+ try {
+ $user = $profile->getUser();
$paths[] = array('showstream', $user->nickname, null);
+ } catch (NoSuchUserException $e) {
+ // We really should handle the remote profile views too
+ $user = null;
}
// Add to the public timeline
- if ($notice->is_local == Notice::LOCAL_PUBLIC ||
- ($notice->is_local == Notice::REMOTE_OMB && !common_config('public', 'localonly'))) {
+ $is_local = intval($notice->is_local);
+ if ($is_local === Notice::LOCAL_PUBLIC ||
+ ($is_local === Notice::REMOTE && !common_config('public', 'localonly'))) {
$paths[] = array('public', null, null);
}
$ni = $notice->whoGets();
foreach (array_keys($ni) as $user_id) {
- $user = User::staticGet('id', $user_id);
+ $user = User::getKV('id', $user_id);
$paths[] = array('all', $user->nickname, null);
}
if ($reply->find()) {
while ($reply->fetch()) {
- $user = User::staticGet('id', $reply->profile_id);
+ $user = User::getKV('id', $reply->profile_id);
if (!empty($user)) {
$paths[] = array('replies', $user->nickname, null);
}
if ($gi->find()) {
while ($gi->fetch()) {
- $ug = User_group::staticGet('id', $gi->group_id);
+ $ug = User_group::getKV('id', $gi->group_id);
$paths[] = array('showgroup', $ug->nickname, null);
}
}
$json = $this->noticeAsJson($notice);
$this->_connect();
-
+
// XXX: We should probably fan-out here and do a
// new queue item for each path
foreach ($paths as $path) {
-
- list($action, $arg1, $arg2) = $path;
-
- $channels = Realtime_channel::getAllChannels($action, $arg1, $arg2);
-
- foreach ($channels as $channel) {
-
- // XXX: We should probably fan-out here and do a
- // new queue item for each user/path combo
-
- if (is_null($channel->user_id)) {
- $profile = null;
- } else {
- $profile = Profile::staticGet('id', $channel->user_id);
- }
- if ($notice->inScope($profile)) {
- $timeline = $this->_pathToChannel(array($channel->channel_key));
- $this->_publish($timeline, $json);
- }
- }
+
+ list($action, $arg1, $arg2) = $path;
+
+ $channels = Realtime_channel::getAllChannels($action, $arg1, $arg2);
+ $this->log(LOG_INFO, sprintf(_("%d candidate channels for notice %d"),
+ count($channels),
+ $notice->id));
+
+ foreach ($channels as $channel) {
+
+ // XXX: We should probably fan-out here and do a
+ // new queue item for each user/path combo
+
+ if (is_null($channel->user_id)) {
+ $profile = null;
+ } else {
+ $profile = Profile::getKV('id', $channel->user_id);
+ }
+ if ($notice->inScope($profile)) {
+ $this->log(LOG_INFO,
+ sprintf(_("Delivering notice %d to channel (%s, %s, %s) for user '%s'"),
+ $notice->id,
+ $channel->action,
+ $channel->arg1,
+ $channel->arg2,
+ ($profile) ? ($profile->nickname) : "<public>"));
+ $timeline = $this->_pathToChannel(array($channel->channel_key));
+ $this->_publish($timeline, $json);
+ }
+ }
}
$this->_disconnect();
// root url from page output
$action->elementStart('address');
+
+ if (common_config('singleuser', 'enabled')) {
+ $user = User::singleUser();
+ $url = common_local_url('showstream', array('nickname' => $user->nickname));
+ } else {
+ $url = common_local_url('public');
+ }
+
$action->element('a', array('class' => 'url',
- 'href' => common_local_url('public')),
+ 'href' => $url),
'');
+
$action->elementEnd('address');
$action->showContentBlock();
$act = new ApiAction('/dev/null');
$arr = $act->twitterStatusArray($notice, true);
- $arr['url'] = $notice->bestUrl();
- $arr['html'] = htmlspecialchars($notice->rendered);
+ $arr['url'] = $notice->getUrl(true);
+ $arr['html'] = htmlspecialchars($notice->getRendered());
$arr['source'] = htmlspecialchars($arr['source']);
- $arr['conversation_url'] = $this->getConversationUrl($notice);
+ $arr['conversation_url'] = $notice->getConversationUrl();
$profile = $notice->getProfile();
$arr['user']['profile_url'] = $profile->profileurl;
// Add needed repeat data
if (!empty($notice->repeat_of)) {
- $original = Notice::staticGet('id', $notice->repeat_of);
- if (!empty($original)) {
- $arr['retweeted_status']['url'] = $original->bestUrl();
- $arr['retweeted_status']['html'] = htmlspecialchars($original->rendered);
+ $original = Notice::getKV('id', $notice->repeat_of);
+ if ($original instanceof Notice) {
+ $arr['retweeted_status']['url'] = $original->getUrl(true);
+ $arr['retweeted_status']['html'] = htmlspecialchars($original->getRendered());
$arr['retweeted_status']['source'] = htmlspecialchars($original->source);
$originalProfile = $original->getProfile();
$arr['retweeted_status']['user']['profile_url'] = $originalProfile->profileurl;
- $arr['retweeted_status']['conversation_url'] = $this->getConversationUrl($original);
+ $arr['retweeted_status']['conversation_url'] = $original->getConversationUrl();
}
- $original = null;
+ unset($original);
}
return $arr;
return $tags;
}
- function getConversationUrl($notice)
- {
- $convurl = null;
-
- if ($notice->hasConversation()) {
- $conv = Conversation::staticGet(
- 'id',
- $notice->conversation
- );
- $convurl = $conv->uri;
-
- if(empty($convurl)) {
- $msg = sprintf(
- "Couldn't find Conversation ID %d to make 'in context'"
- . "link for Notice ID %d",
- $notice->conversation,
- $notice->id
- );
-
- common_log(LOG_WARNING, $msg);
- } else {
- $convurl .= '#notice-' . $notice->id;
- }
- }
-
- return $convurl;
- }
-
function _getScripts()
{
- if (common_config('site', 'minify')) {
- $js = 'realtimeupdate.min.js';
- } else {
- $js = 'realtimeupdate.js';
- }
- return array(Plugin::staticPath('Realtime', $js));
+ $urlpath = self::staticPath(str_replace('Plugin','',__CLASS__),
+ 'js/realtimeupdate.js');
+ return array($urlpath);
}
/**
function _getChannel($action)
{
$timeline = null;
- $arg1 = null;
- $arg2 = null;
-
+ $arg1 = null;
+ $arg2 = null;
+
$action_name = $action->trimmed('action');
- // FIXME: lists
- // FIXME: search (!)
- // FIXME: profile + tag
-
+ // FIXME: lists
+ // FIXME: search (!)
+ // FIXME: profile + tag
+
switch ($action_name) {
case 'public':
- // no arguments
+ // no arguments
break;
case 'tag':
$tag = $action->trimmed('tag');
- if (empty($tag)) {
+ if (!empty($tag)) {
$arg1 = $tag;
} else {
- $this->log(LOG_NOTICE, "Unexpected 'tag' action without tag argument");
- return null;
+ $this->log(LOG_NOTICE, "Unexpected 'tag' action without tag argument");
+ return null;
}
break;
case 'showstream':
if (!empty($nickname)) {
$arg1 = $nickname;
} else {
- $this->log(LOG_NOTICE, "Unexpected $action_name action without nickname argument.");
- return null;
+ $this->log(LOG_NOTICE, "Unexpected $action_name action without nickname argument.");
+ return null;
}
break;
default:
return null;
}
- $user = common_current_user();
-
- $user_id = (!empty($user)) ? $user->id : null;
-
- $channel = Realtime_channel::getChannel($user_id,
- $action_name,
- $arg1,
- $arg2);
+ $user = common_current_user();
+
+ $user_id = (!empty($user)) ? $user->id : null;
+
+ $channel = Realtime_channel::getChannel($user_id,
+ $action_name,
+ $arg1,
+ $arg2);
return $channel;
}
-
+
function onStartReadWriteTables(&$alwaysRW, &$rwdb)
{
- $alwaysRW[] = 'realtime_channel';
- return true;
+ $alwaysRW[] = 'realtime_channel';
+ return true;
}
}