Merge branch '0.8.x' into small-fixes

This commit is contained in:
Jeffery To 2009-06-26 15:44:31 +08:00
commit 612a107e09
49 changed files with 881 additions and 380 deletions

View File

@ -63,6 +63,7 @@ class ConversationAction extends Action
if (empty($this->id)) {
return false;
}
$this->id = $this->id+0;
$this->page = $this->trimmed('page');
if (empty($this->page)) {
$this->page = 1;
@ -106,18 +107,10 @@ class ConversationAction extends Action
function showContent()
{
// FIXME this needs to be a tree, not a list
$qry = 'SELECT * FROM notice WHERE conversation = %s ';
$offset = ($this->page-1) * NOTICES_PER_PAGE;
$limit = NOTICES_PER_PAGE + 1;
$txt = sprintf($qry, $this->id);
$notices = Notice::getStream($txt,
'notice:conversation:'.$this->id,
$offset, $limit);
$notices = Notice::conversationStream($this->id, $offset, $limit);
$ct = new ConversationTree($notices, $this);
@ -126,7 +119,6 @@ class ConversationAction extends Action
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'conversation', array('id' => $this->id));
}
}
/**

View File

@ -21,20 +21,40 @@ if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/actions/shownotice.php');
class FileAction extends ShowNoticeAction
class FileAction extends Action
{
function showPage() {
$source_url = common_local_url('file', array('notice' => $this->notice->id));
$query = "select file_redirection.url as url from file join file_redirection on file.id = file_redirection.file_id where file.url = '$source_url'";
$file = new File_redirection;
$file->query($query);
$file->fetch();
if (empty($file->url)) {
die('nothing attached here');
} else {
header("Location: {$file->url}");
die();
var $id = null;
var $filerec = null;
function prepare($args)
{
parent::prepare($args);
$this->id = $this->trimmed('notice');
if (empty($this->id)) {
$this->clientError(_('No notice id'));
}
$notice = Notice::staticGet('id', $this->id);
if (empty($notice)) {
$this->clientError(_('No notice'));
}
$atts = $notice->attachments();
if (empty($atts)) {
$this->clientError(_('No attachments'));
}
foreach ($atts as $att) {
if (!empty($att->filename)) {
$this->filerec = $att;
break;
}
}
if (empty($this->filerec)) {
$this->clientError(_('No uploaded attachments'));
}
return true;
}
function handle() {
common_redirect($this->filerec->url);
}
}

View File

@ -238,7 +238,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction
$design->sidebarcolor = $sbcolor->intValue();
$design->textcolor = $tcolor->intValue();
$design->linkcolor = $lcolor->intValue();
$design->backgroundimage = $filepath;
$design->setDisposition($on, $off, $tile);
@ -263,7 +262,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction
$design->sidebarcolor = $sbcolor->intValue();
$design->textcolor = $tcolor->intValue();
$design->linkcolor = $lcolor->intValue();
$design->backgroundimage = $filepath;
$design->setDisposition($on, $off, $tile);

View File

@ -236,6 +236,7 @@ class NewnoticeAction extends Action
$this->deleteFile($filename);
$this->clientError(_('Max notice size is 140 chars, including attachment URL.'));
}
$fileRecord = $this->rememberFile($filename, $mimetype, $short_fileurl);
}
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
@ -249,7 +250,7 @@ class NewnoticeAction extends Action
}
if (isset($mimetype)) {
$this->attachFile($notice, $filename, $mimetype, $short_fileurl);
$this->attachFile($notice, $fileRecord);
}
common_broadcast_notice($notice);
@ -304,12 +305,12 @@ class NewnoticeAction extends Action
@unlink($filepath);
}
function attachFile($notice, $filename, $mimetype, $short)
function rememberFile($filename, $mimetype, $short)
{
$file = new File;
$file->filename = $filename;
$file->url = common_local_url('file', array('notice' => $notice->id));
$file->url = File::url($filename);
$filepath = File::path($filename);
@ -324,26 +325,35 @@ class NewnoticeAction extends Action
$this->clientError(_('There was a database error while saving your file. Please try again.'));
}
$file_redir = new File_redirection;
$file_redir->url = File::url($filename);
$file_redir->file_id = $file_id;
$this->maybeAddRedir($file_id, $short);
$result = $file_redir->insert();
return $file;
}
if (!$result) {
common_log_db_error($file_redir, "INSERT", __FILE__);
$this->clientError(_('There was a database error while saving your file. Please try again.'));
function maybeAddRedir($file_id, $url)
{
$file_redir = File_redirection::staticGet('url', $url);
if (empty($file_redir)) {
$file_redir = new File_redirection;
$file_redir->url = $url;
$file_redir->file_id = $file_id;
$result = $file_redir->insert();
if (!$result) {
common_log_db_error($file_redir, "INSERT", __FILE__);
$this->clientError(_('There was a database error while saving your file. Please try again.'));
}
}
}
$f2p = new File_to_post;
$f2p->file_id = $file_id;
$f2p->post_id = $notice->id;
$f2p->insert();
function attachFile($notice, $filerec)
{
File_to_post::processNew($filerec->id, $notice->id);
if (!$result) {
common_log_db_error($f2p, "INSERT", __FILE__);
$this->clientError(_('There was a database error while saving your file. Please try again.'));
}
$this->maybeAddRedir($filerec->id,
common_local_url('file', array('notice' => $notice->id)));
}
/**

View File

@ -35,6 +35,10 @@ require_once INSTALLDIR.'/lib/publicgroupnav.php';
require_once INSTALLDIR.'/lib/noticelist.php';
require_once INSTALLDIR.'/lib/feedlist.php';
// Farther than any human will go
define('MAX_PUBLIC_PAGE', 100);
/**
* Action for displaying the public stream
*
@ -74,6 +78,10 @@ class PublicAction extends Action
parent::prepare($args);
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
if ($this->page > MAX_PUBLIC_PAGE) {
$this->clientError(sprintf(_("Beyond the page limit (%s)"), MAX_PUBLIC_PAGE));
}
common_set_returnto($this->selfUrl());
return true;

View File

@ -191,10 +191,21 @@ class ShowfavoritesAction extends CurrentUserDesignAction
function showContent()
{
$notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1);
$cur = common_current_user();
if (!$notice) {
if (!empty($cur) && $cur->id == $this->user->id) {
// Show imported/gateway notices as well as local if
// the user is looking at his own favorites
$notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1, true);
} else {
$notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1, false);
}
if (empty($notice)) {
$this->serverError(_('Could not retrieve favorite notices.'));
return;
}

View File

@ -61,7 +61,11 @@ class TwitapifavoritesAction extends TwitterapiAction
$since_id = (int)$this->arg('since_id', 0);
$since = $this->arg('since');
$notice = $user->favoriteNotices(($page-1)*$count, $count);
if (!empty($this->auth_user) && $this->auth_user->id == $user->id) {
$notice = $user->favoriteNotices(($page-1)*$count, $count, true);
} else {
$notice = $user->favoriteNotices(($page-1)*$count, $count, false);
}
switch($apidata['content-type']) {
case 'xml':

View File

@ -75,8 +75,8 @@ class TwitapistatusesAction extends TwitterapiAction
{
parent::handle($args);
$this->auth_user = $apidata['user'];
$user = $this->get_user($apidata['api_arg'], $apidata);
$this->auth_user = $user;
if (empty($user)) {
$this->clientError(_('No such user!'), 404,
@ -100,8 +100,13 @@ class TwitapistatusesAction extends TwitterapiAction
$since_id = (int)$this->arg('since_id', 0);
$since = $this->arg('since');
$notice = $user->noticesWithFriends(($page-1)*$count,
$count, $since_id, $max_id,$since);
if (!empty($this->auth_user) && $this->auth_user->id == $user->id) {
$notice = $user->noticeInbox(($page-1)*$count,
$count, $since_id, $max_id, $since);
} else {
$notice = $user->noticesWithFriends(($page-1)*$count,
$count, $since_id, $max_id, $since);
}
switch($apidata['content-type']) {
case 'xml':

View File

@ -149,7 +149,6 @@ class UserDesignSettingsAction extends DesignSettingsAction
$design->sidebarcolor = $sbcolor->intValue();
$design->textcolor = $tcolor->intValue();
$design->linkcolor = $lcolor->intValue();
$design->backgroundimage = $filepath;
$design->setDisposition($on, $off, $tile);
@ -174,7 +173,6 @@ class UserDesignSettingsAction extends DesignSettingsAction
$design->sidebarcolor = $sbcolor->intValue();
$design->textcolor = $tcolor->intValue();
$design->linkcolor = $lcolor->intValue();
$design->backgroundimage = $filepath;
$design->setDisposition($on, $off, $tile);

View File

@ -37,52 +37,62 @@ class Fave extends Memcached_DataObject
return Memcached_DataObject::pkeyGet('Fave', $kv);
}
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE)
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false)
{
$ids = Notice::stream(array('Fave', '_streamDirect'),
array($user_id),
'fave:ids_by_user:'.$user_id,
array($user_id, $own),
($own) ? 'fave:ids_by_user_own:'.$user_id :
'fave:by_user:'.$user_id,
$offset, $limit);
return $ids;
}
function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since)
function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id, $since)
{
$fav = new Fave();
$qry = null;
$fav->user_id = $user_id;
$fav->selectAdd();
$fav->selectAdd('notice_id');
if ($own) {
$qry = 'SELECT fave.* FROM fave ';
$qry .= 'WHERE fave.user_id = ' . $user_id . ' ';
} else {
$qry = 'SELECT fave.* FROM fave ';
$qry .= 'INNER JOIN notice ON fave.notice_id = notice.id ';
$qry .= 'WHERE fave.user_id = ' . $user_id . ' ';
$qry .= 'AND notice.is_local != ' . NOTICE_GATEWAY . ' ';
}
if ($since_id != 0) {
$fav->whereAdd('notice_id > ' . $since_id);
$qry .= 'AND notice_id > ' . $since_id . ' ';
}
if ($max_id != 0) {
$fav->whereAdd('notice_id <= ' . $max_id);
$qry .= 'AND notice_id <= ' . $max_id . ' ';
}
if (!is_null($since)) {
$fav->whereAdd('modified > \'' . date('Y-m-d H:i:s', $since) . '\'');
$qry .= 'AND modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
}
// NOTE: we sort by fave time, not by notice time!
$fav->orderBy('modified DESC');
$qry .= 'ORDER BY modified DESC ';
if (!is_null($offset)) {
$fav->limit($offset, $limit);
$qry .= "LIMIT $offset, $limit";
}
$fav->query($qry);
$ids = array();
if ($fav->find()) {
while ($fav->fetch()) {
$ids[] = $fav->notice_id;
}
while ($fav->fetch()) {
$ids[] = $fav->notice_id;
}
$fav->free();
unset($fav);
return $ids;
}
}

View File

@ -91,9 +91,10 @@ class File extends Memcached_DataObject
$given_url = File_redirection::_canonUrl($given_url);
if (empty($given_url)) return -1; // error, no url to process
$file = File::staticGet('url', $given_url);
if (empty($file->id)) {
if (empty($file)) {
$file_redir = File_redirection::staticGet('url', $given_url);
if (empty($file_redir->id)) {
if (empty($file_redir)) {
common_debug("processNew() '$given_url' not a known redirect.\n");
$redir_data = File_redirection::where($given_url);
$redir_url = $redir_data['url'];
if ($redir_url === $given_url) {

View File

@ -66,21 +66,17 @@ class File_redirection extends Memcached_DataObject
// let's see if we know this...
$a = File::staticGet('url', $short_url);
if (empty($a->id)) {
$b = File_redirection::staticGet('url', $short_url);
if (empty($b->id)) {
// we'll have to figure it out
} else {
// this is a redirect to $b->file_id
$a = File::staticGet($b->file_id);
$url = $a->url;
}
} else {
if (!empty($a)) {
// this is a direct link to $a->url
$url = $a->url;
}
if (isset($url)) {
return $url;
return $a->url;
} else {
$b = File_redirection::staticGet('url', $short_url);
if (!empty($b)) {
// this is a redirect to $b->file_id
$a = File::staticGet('id', $b->file_id);
return $a->url;
}
}
$curlh = File_redirection::_commonCurl($short_url, $redirs);
@ -118,28 +114,22 @@ class File_redirection extends Memcached_DataObject
}
function makeShort($long_url) {
$long_url = File_redirection::_canonUrl($long_url);
// do we already know this long_url and have a short redirection for it?
$file = new File;
$file_redir = new File_redirection;
$file->url = $long_url;
$file->joinAdd($file_redir);
$file->selectAdd('length(file_redirection.url) as len');
$file->limit(1);
$file->orderBy('len');
$file->find(true);
if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) {
return $file->url;
}
// if yet unknown, we must find a short url according to user settings
$short_url = File_redirection::_userMakeShort($long_url, common_current_user());
return $short_url;
$canon = File_redirection::_canonUrl($long_url);
$short_url = File_redirection::_userMakeShort($canon);
// Did we get one? Is it shorter?
if (!empty($short_url) && mb_strlen($short_url) < mb_strlen($long_url)) {
return $short_url;
} else {
return $long_url;
}
}
function _userMakeShort($long_url, $user) {
function _userMakeShort($long_url) {
$short_url = common_shorten_url($long_url);
if ($short_url) {
if (!empty($short_url) && $short_url != $long_url) {
$short_url = (string)$short_url;
// store it
$file = File::staticGet('url', $long_url);
@ -162,7 +152,7 @@ class File_redirection extends Memcached_DataObject
}
return $short_url;
}
return $long_url;
return null;
}
function _canonUrl($in_url, $default_scheme = 'http://') {

View File

@ -25,7 +25,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
* Table Definition for file_to_post
*/
class File_to_post extends Memcached_DataObject
class File_to_post extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
@ -44,17 +44,27 @@ class File_to_post extends Memcached_DataObject
function processNew($file_id, $notice_id) {
static $seen = array();
if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) {
$f2p = new File_to_post;
$f2p->file_id = $file_id;
$f2p->post_id = $notice_id;
$f2p->insert();
$f2p = File_to_post::pkeyGet(array('post_id' => $notice_id,
'file_id' => $file_id));
if (empty($f2p)) {
$f2p = new File_to_post;
$f2p->file_id = $file_id;
$f2p->post_id = $notice_id;
$f2p->insert();
}
if (empty($seen[$notice_id])) {
$seen[$notice_id] = array($file_id);
} else {
$seen[$notice_id][] = $file_id;
}
}
}
function &pkeyGet($kv)
{
return Memcached_DataObject::pkeyGet('File_to_post', $kv);
}
}

View File

@ -4,42 +4,41 @@
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Foreign_user extends Memcached_DataObject
class Foreign_user extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'foreign_user'; // table name
public $id; // int(4) primary_key not_null
public $id; // bigint(8) primary_key not_null
public $service; // int(4) primary_key not_null
public $uri; // varchar(255) unique_key not_null
public $nickname; // varchar(255)
public $nickname; // varchar(255)
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k,$v=null)
{ return Memcached_DataObject::staticGet('Foreign_user',$k,$v); }
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Foreign_user',$k,$v); }
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
// XXX: This only returns a 1->1 single obj mapping. Change? Or make
// a getForeignUsers() that returns more than one? --Zach
static function getForeignUser($id, $service) {
static function getForeignUser($id, $service) {
$fuser = new Foreign_user();
$fuser->whereAdd("service = $service");
$fuser->whereAdd("id = $id");
$fuser->limit(1);
if ($fuser->find()) {
$fuser->fetch();
return $fuser;
}
return null;
return null;
}
function updateKeys(&$orig)
{
$parts = array();
@ -68,5 +67,4 @@ class Foreign_user extends Memcached_DataObject
return $result;
}
}

View File

@ -14,8 +14,14 @@ class Group_inbox extends Memcached_DataObject
public $created; // datetime() not_null
/* Static get */
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Group_inbox',$k,$v); }
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
function &pkeyGet($kv)
{
return Memcached_DataObject::pkeyGet('Group_inbox', $kv);
}
}

View File

@ -331,6 +331,20 @@ class Notice extends Memcached_DataObject
return $n_attachments;
}
function attachments() {
// XXX: cache this
$att = array();
$f2p = new File_to_post;
$f2p->post_id = $this->id;
if ($f2p->find()) {
while ($f2p->fetch()) {
$f = File::staticGet($f2p->file_id);
$att[] = clone($f);
}
}
return $att;
}
function blowCaches($blowLast=false)
{
$this->blowSubsCache($blowLast);
@ -339,6 +353,19 @@ class Notice extends Memcached_DataObject
$this->blowPublicCache($blowLast);
$this->blowTagCache($blowLast);
$this->blowGroupCache($blowLast);
$this->blowConversationCache($blowLast);
}
function blowConversationCache($blowLast=false)
{
$cache = common_memcache();
if ($cache) {
$ck = common_cache_key('notice:conversation_ids:'.$this->conversation);
$cache->delete($ck);
if ($blowLast) {
$cache->delete($ck.';last');
}
}
}
function blowGroupCache($blowLast=false)
@ -471,8 +498,10 @@ class Notice extends Memcached_DataObject
if ($fave->find()) {
while ($fave->fetch()) {
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id));
$cache->delete(common_cache_key('fave:by_user_own:'.$fave->user_id));
if ($blowLast) {
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id.';last'));
$cache->delete(common_cache_key('fave:by_user_own:'.$fave->user_id.';last'));
}
}
}
@ -675,7 +704,10 @@ class Notice extends Memcached_DataObject
if (!empty($cache)) {
$notices = array();
foreach ($ids as $id) {
$notices[] = Notice::staticGet('id', $id);
$n = Notice::staticGet('id', $id);
if (!empty($n)) {
$notices[] = $n;
}
}
return new ArrayWrapper($notices);
} else {
@ -744,29 +776,116 @@ class Notice extends Memcached_DataObject
return $ids;
}
function conversationStream($id, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
{
$ids = Notice::stream(array('Notice', '_conversationStreamDirect'),
array($id),
'notice:conversation_ids:'.$id,
$offset, $limit, $since_id, $max_id, $since);
return Notice::getStreamByIds($ids);
}
function _conversationStreamDirect($id, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
{
$notice = new Notice();
$notice->selectAdd(); // clears it
$notice->selectAdd('id');
$notice->whereAdd('conversation = '.$id);
$notice->orderBy('id DESC');
if (!is_null($offset)) {
$notice->limit($offset, $limit);
}
if ($since_id != 0) {
$notice->whereAdd('id > ' . $since_id);
}
if ($max_id != 0) {
$notice->whereAdd('id <= ' . $max_id);
}
if (!is_null($since)) {
$notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
}
$ids = array();
if ($notice->find()) {
while ($notice->fetch()) {
$ids[] = $notice->id;
}
}
$notice->free();
$notice = NULL;
return $ids;
}
function addToInboxes()
{
$enabled = common_config('inboxes', 'enabled');
if ($enabled === true || $enabled === 'transitional') {
$inbox = new Notice_inbox();
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' .
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " .
"FROM $UT JOIN subscription ON $UT.id = subscription.subscriber " .
'WHERE subscription.subscribed = ' . $this->profile_id . ' ' .
'AND NOT EXISTS (SELECT user_id, notice_id ' .
'FROM notice_inbox ' .
"WHERE user_id = $UT.id " .
'AND notice_id = ' . $this->id . ' )';
if ($enabled === 'transitional') {
$qry .= " AND $UT.inboxed = 1";
$users = $this->getSubscribedUsers();
// FIXME: kind of ignoring 'transitional'...
// we'll probably stop supporting inboxless mode
// in 0.9.x
foreach ($users as $id) {
$this->addToUserInbox($id, NOTICE_INBOX_SOURCE_SUB);
}
$inbox->query($qry);
}
return;
}
function getSubscribedUsers()
{
$user = new User();
$qry =
'SELECT id ' .
'FROM user JOIN subscription '.
'ON user.id = subscription.subscriber ' .
'WHERE subscription.subscribed = %d ';
$user->query(sprintf($qry, $this->profile_id));
$ids = array();
while ($user->fetch()) {
$ids[] = $user->id;
}
$user->free();
return $ids;
}
function addToUserInbox($user_id, $source)
{
$inbox = Notice_inbox::pkeyGet(array('user_id' => $user_id,
'notice_id' => $this->id));
if (empty($inbox)) {
$inbox = new Notice_inbox();
$inbox->user_id = $user_id;
$inbox->notice_id = $this->id;
$inbox->source = $source;
$inbox->created = $this->created;
return $inbox->insert();
}
return true;
}
function saveGroups()
{
$enabled = common_config('inboxes', 'enabled');
@ -805,13 +924,7 @@ class Notice extends Memcached_DataObject
if ($profile->isMember($group)) {
$gi = new Group_inbox();
$gi->group_id = $group->id;
$gi->notice_id = $this->id;
$gi->created = common_sql_now();
$result = $gi->insert();
$result = $this->addToGroupInbox($group);
if (!$result) {
common_log_db_error($gi, 'INSERT', __FILE__);
@ -819,27 +932,37 @@ class Notice extends Memcached_DataObject
// FIXME: do this in an offline daemon
$this->addToGroupInboxes($group);
$this->addToGroupMemberInboxes($group);
}
}
}
function addToGroupInboxes($group)
function addToGroupInbox($group)
{
$inbox = new Notice_inbox();
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "', " . NOTICE_INBOX_SOURCE_GROUP . " " .
"FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " .
'WHERE group_member.group_id = ' . $group->id . ' ' .
'AND NOT EXISTS (SELECT user_id, notice_id ' .
'FROM notice_inbox ' .
"WHERE user_id = $UT.id " .
'AND notice_id = ' . $this->id . ' )';
if ($enabled === 'transitional') {
$qry .= " AND $UT.inboxed = 1";
$gi = Group_inbox::pkeyGet(array('group_id' => $group->id,
'notice_id' => $this->id));
if (empty($gi)) {
$gi = new Group_inbox();
$gi->group_id = $group->id;
$gi->notice_id = $this->id;
$gi->created = $this->created;
return $gi->insert();
}
return true;
}
function addToGroupMemberInboxes($group)
{
$users = $group->getUserMembers();
foreach ($users as $id) {
$this->addToUserInbox($id, NOTICE_INBOX_SOURCE_GROUP);
}
$result = $inbox->query($qry);
}
function saveReplies()

View File

@ -27,6 +27,7 @@ define('INBOX_CACHE_WINDOW', 101);
define('NOTICE_INBOX_SOURCE_SUB', 1);
define('NOTICE_INBOX_SOURCE_GROUP', 2);
define('NOTICE_INBOX_SOURCE_REPLY', 3);
define('NOTICE_INBOX_SOURCE_GATEWAY', -1);
class Notice_inbox extends Memcached_DataObject

View File

@ -289,4 +289,52 @@ class Profile extends Memcached_DataObject
return Avatar::defaultImage($size);
}
}
function getSubscriptions($offset=0, $limit=null)
{
$qry =
'SELECT profile.* ' .
'FROM profile JOIN subscription ' .
'ON profile.id = subscription.subscribed ' .
'WHERE subscription.subscriber = %d ' .
'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC ';
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = new Profile();
$profile->query(sprintf($qry, $this->id));
return $profile;
}
function getSubscribers($offset=0, $limit=null)
{
$qry =
'SELECT profile.* ' .
'FROM profile JOIN subscription ' .
'ON profile.id = subscription.subscriber ' .
'WHERE subscription.subscribed = %d ' .
'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC ';
if ($offset) {
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
}
$profile = new Profile();
$cnt = $profile->query(sprintf($qry, $this->id));
return $profile;
}
}

View File

@ -424,9 +424,9 @@ class User extends Memcached_DataObject
}
}
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE)
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE, $own=false)
{
$ids = Fave::stream($this->id, $offset, $limit);
$ids = Fave::stream($this->id, $offset, $limit, $own);
return Notice::getStreamByIds($ids);
}
@ -600,50 +600,16 @@ class User extends Memcached_DataObject
function getSubscriptions($offset=0, $limit=null)
{
$qry =
'SELECT profile.* ' .
'FROM profile JOIN subscription ' .
'ON profile.id = subscription.subscribed ' .
'WHERE subscription.subscriber = %d ' .
'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC ';
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = new Profile();
$profile->query(sprintf($qry, $this->id));
return $profile;
$profile = $this->getProfile();
assert(!empty($profile));
return $profile->getSubscriptions($offset, $limit);
}
function getSubscribers($offset=0, $limit=null)
{
$qry =
'SELECT profile.* ' .
'FROM profile JOIN subscription ' .
'ON profile.id = subscription.subscriber ' .
'WHERE subscription.subscribed = %d ' .
'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC ';
if ($offset) {
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
}
$profile = new Profile();
$cnt = $profile->query(sprintf($qry, $this->id));
return $profile;
$profile = $this->getProfile();
assert(!empty($profile));
return $profile->getSubscribers($offset, $limit);
}
function getTaggedSubscribers($tag, $offset=0, $limit=null)

View File

@ -246,4 +246,28 @@ class User_group extends Memcached_DataObject
return Design::staticGet('id', $this->design_id);
}
function getUserMembers()
{
// XXX: cache this
$user = new User();
$qry =
'SELECT id ' .
'FROM user JOIN group_member '.
'ON user.id = group_member.profile_id ' .
'WHERE group_member.group_id = %d ';
$user->query(sprintf($qry, $this->id));
$ids = array();
while ($user->fetch()) {
$ids[] = $user->id;
}
$user->free();
return $ids;
}
}

109
db/074to080.sql Normal file
View File

@ -0,0 +1,109 @@
alter table user
add column design_id integer comment 'id of a design' references design(id),
add column viewdesigns tinyint default 1 comment 'whether to view user-provided designs';
alter table notice add column
conversation integer comment 'id of root notice in this conversation' references notice (id),
add index notice_conversation_idx (conversation);
alter table foreign_user
modify column id bigint not null comment 'unique numeric key on foreign service';
alter table foreign_link
modify column foreign_id bigint unsigned comment 'link to user on foreign service, if exists';
alter table user_group
add column design_id integer comment 'id of a design' references design(id);
create table file (
id integer primary key auto_increment,
url varchar(255) comment 'destination URL after following redirections',
mimetype varchar(50) comment 'mime type of resource',
size integer comment 'size of resource when available',
title varchar(255) comment 'title of resource when available',
date integer(11) comment 'date of resource according to http query',
protected integer(1) comment 'true when URL is private (needs login)',
filename varchar(255) comment 'if a local file, name of the file',
modified timestamp comment 'date this record was modified',
unique(url)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
create table file_oembed (
file_id integer primary key comment 'oEmbed for that URL/file' references file (id),
version varchar(20) comment 'oEmbed spec. version',
type varchar(20) comment 'oEmbed type: photo, video, link, rich',
provider varchar(50) comment 'name of this oEmbed provider',
provider_url varchar(255) comment 'URL of this oEmbed provider',
width integer comment 'width of oEmbed resource when available',
height integer comment 'height of oEmbed resource when available',
html text comment 'html representation of this oEmbed resource when applicable',
title varchar(255) comment 'title of oEmbed resource when available',
author_name varchar(50) comment 'author name for this oEmbed resource',
author_url varchar(255) comment 'author URL for this oEmbed resource',
url varchar(255) comment 'URL for this oEmbed resource when applicable (photo, link)',
modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
create table file_redirection (
url varchar(255) primary key comment 'short URL (or any other kind of redirect) for file (id)',
file_id integer comment 'short URL for what URL/file' references file (id),
redirections integer comment 'redirect count',
httpcode integer comment 'HTTP status code (20x, 30x, etc.)',
modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table file_thumbnail (
file_id integer primary key comment 'thumbnail for what URL/file' references file (id),
url varchar(255) comment 'URL of thumbnail',
width integer comment 'width of thumbnail',
height integer comment 'height of thumbnail',
modified timestamp comment 'date this record was modified',
unique(url)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table file_to_post (
file_id integer comment 'id of URL/file' references file (id),
post_id integer comment 'id of the notice it belongs to' references notice (id),
modified timestamp comment 'date this record was modified',
constraint primary key (file_id, post_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table design (
id integer primary key auto_increment comment 'design ID',
backgroundcolor integer comment 'main background color',
contentcolor integer comment 'content area background color',
sidebarcolor integer comment 'sidebar background color',
textcolor integer comment 'text color',
linkcolor integer comment 'link color',
backgroundimage varchar(255) comment 'background image, if any',
disposition tinyint default 1 comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table group_block (
group_id integer not null comment 'group profile is blocked from' references user_group (id),
blocked integer not null comment 'profile that is blocked' references profile (id),
blocker integer not null comment 'user making the block' references user (id),
modified timestamp comment 'date of blocking',
constraint primary key (group_id, blocked)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table group_alias (
alias varchar(64) primary key comment 'additional nickname for the group',
group_id integer not null comment 'group profile is blocked from' references user_group (id),
modified timestamp comment 'date alias was created',
index group_alias_group_id_idx (group_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;

View File

@ -277,7 +277,7 @@ create table foreign_service (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table foreign_user (
id int not null comment 'unique numeric key on foreign service',
id bigint not null comment 'unique numeric key on foreign service',
service int not null comment 'foreign key to service' references foreign_service(id),
uri varchar(255) not null unique key comment 'identifying URI',
nickname varchar(255) comment 'nickname on foreign service',

View File

@ -48,7 +48,14 @@ function handleError($error)
$logmsg .= " : ". $error->getDebugInfo();
}
common_log(LOG_ERR, $logmsg);
if ($error instanceof DB_DataObject_Error) {
if(common_config('site', 'logdebug')) {
$bt = $error->getBacktrace();
foreach ($bt as $line) {
common_log(LOG_ERR, $line);
}
}
if ($error instanceof DB_DataObject_Error ||
$error instanceof DB_Error) {
$msg = sprintf(_('The database for %s isn\'t responding correctly, '.
'so the site won\'t work properly. '.
'The site admins probably know about the problem, '.

View File

@ -89,11 +89,10 @@ $(document).ready(function() {
$('body').css({'background-image':'none'});
});
$('#design_background-image_on').focus(function() {
var bis = $('#design_background-image_onoff img')[0].src;
$('body').css({'background-image':'url('+bis+')'});
$('body').css({'background-image':'url('+$('#design_background-image_onoff img')[0].src+')'});
});
$('#design_background-image_repeat').click(function() {
($(this)[0].checked) ? $('body').css({'background-repeat':'repeat'}) : $('body').css({'background-repeat':'no-repeat'});
});
});
});

View File

@ -222,6 +222,7 @@ $(document).ready(function(){
}
$("#notice_data-text").val("");
$("#notice_data-attach").val("");
$('#notice_data-attach_selected').remove();
counter();
}
$("#form_notice").removeClass("processing");
@ -233,6 +234,7 @@ $(document).ready(function(){
$("#form_notice").each(addAjaxHidden);
NoticeReply();
NoticeAttachments();
NoticeDataAttach();
});
function NoticeReply() {
@ -280,13 +282,13 @@ function NoticeAttachments() {
timeout : 0
};
$('a.attachment').click(function() {
$('#content .notice a.attachment').click(function() {
$().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
return false;
});
var t;
$("body:not(#shownotice) a.thumbnail").hover(
$("body:not(#shownotice) #content .notice a.thumbnail").hover(
function() {
var anchor = $(this);
$("a.thumbnail").children('img').hide();
@ -310,3 +312,16 @@ function NoticeAttachments() {
}
);
}
function NoticeDataAttach() {
NDA = $('#notice_data-attach');
NDA.change(function() {
S = '<div id="notice_data-attach_selected" class="success"><code>'+$(this).val()+'</code> <button>&#215;</button></div>';
NDAS = $('#notice_data-attach_selected');
(NDAS.length > 0) ? NDAS.replaceWith(S) : $('#form_notice').append(S);
$('#notice_data-attach_selected button').click(function(){
$('#notice_data-attach_selected').remove();
NDA.val('');
});
});
}

View File

@ -82,7 +82,8 @@ class AttachmentList extends Widget
$atts = new File;
$att = $atts->getAttachments($this->notice->id);
if (empty($att)) return 0;
$this->out->elementStart('dl', array('id' =>'attachments'));
$this->out->elementStart('dl', array('id' =>'attachments',
'class' => 'entry-content'));
$this->out->element('dt', null, _('Attachments'));
$this->out->elementStart('dd');
$this->out->elementStart('ol', array('class' => 'attachments'));
@ -249,10 +250,13 @@ class Attachment extends AttachmentListItem
$this->out->elementStart('div', 'entry-title');
$this->out->elementStart('a', $this->linkAttr());
$this->out->element('span', null, $this->linkTitle());
$this->showRepresentation();
$this->out->elementEnd('a');
$this->out->elementEnd('div');
$this->out->elementStart('div', 'entry-content');
$this->showRepresentation();
$this->out->elementEnd('div');
if (!empty($this->oembed->author_name) || !empty($this->oembed->provider)) {
$this->out->elementStart('div', array('id' => 'oembed_info',
'class' => 'entry-content'));

View File

@ -95,9 +95,9 @@ $config =
'server' => $_server,
'theme' => 'default',
'design' =>
array('backgroundcolor' => '#F0F2F5',
array('backgroundcolor' => '#CEE1E9',
'contentcolor' => '#FFFFFF',
'sidebarcolor' => '#CEE1E9',
'sidebarcolor' => '#C8D1D5',
'textcolor' => '#000000',
'linkcolor' => '#002E6E',
'backgroundimage' => null,
@ -125,7 +125,13 @@ $config =
array('appname' => 'laconica', # for syslog
'priority' => 'debug'), # XXX: currently ignored
'queue' =>
array('enabled' => false),
array('enabled' => false,
'subsystem' => 'db', # default to database, or 'stomp'
'stomp_server' => null,
'queue_basename' => 'laconica',
'stomp_username' => null,
'stomp_password' => null,
),
'license' =>
array('url' => 'http://creativecommons.org/licenses/by/3.0/',
'title' => 'Creative Commons Attribution 3.0',

View File

@ -132,13 +132,13 @@ class DesignSettingsAction extends AccountSettingsAction
_('Off'));
$this->element('p', 'form_guide', _('Turn background image on or off.'));
$this->elementEnd('li');
}
$this->elementStart('li');
$this->checkbox('design_background-image_repeat',
_('Tile background image'),
($design->disposition & BACKGROUND_TILE) ? true : false );
$this->elementEnd('li');
$this->elementStart('li');
$this->checkbox('design_background-image_repeat',
_('Tile background image'),
($design->disposition & BACKGROUND_TILE) ? true : false );
$this->elementEnd('li');
}
$this->elementEnd('ul');
$this->elementEnd('fieldset');
@ -388,7 +388,11 @@ class DesignSettingsAction extends AccountSettingsAction
$original = clone($design);
$design->backgroundimage = $filename;
// default to on, no tile
$design->setDisposition(true, false, false);
$result = $design->update($original);
if ($result === false) {

View File

@ -72,7 +72,8 @@ class ImageFile
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new Exception(sprintf(_('That file is too big. The maximum file size is %d.'), $this->maxFileSize()));
throw new Exception(sprintf(_('That file is too big. The maximum file size is %d.'),
ImageFile::maxFileSize()));
return;
case UPLOAD_ERR_PARTIAL:
@unlink($_FILES[$param]['tmp_name']);

View File

@ -432,7 +432,7 @@ class NoticeListItem extends Widget
$this->out->elementStart('dl', 'response');
$this->out->element('dt', null, _('To'));
$this->out->elementStart('dd');
$this->out->element('a', array('href' => $convurl),
$this->out->element('a', array('href' => $convurl.'#notice-'.$this->notice->id),
_('in context'));
$this->out->elementEnd('dd');
$this->out->elementEnd('dl');

View File

@ -112,12 +112,21 @@ class QueueHandler extends Daemon
}
function stomp_dispatch() {
require("Stomp.php");
$con = new Stomp(common_config('queue','stomp_server'));
if (!$con->connect()) {
// use an external message queue system via STOMP
require_once("Stomp.php");
$server = common_config('queue','stomp_server');
$username = common_config('queue', 'stomp_username');
$password = common_config('queue', 'stomp_password');
$con = new Stomp($server);
if (!$con->connect($username, $password)) {
$this->log(LOG_ERR, 'Failed to connect to queue server');
return false;
}
$queue_basename = common_config('queue','queue_basename');
// subscribe to the relevant queue (format: basename-transport)
$con->subscribe('/queue/'.$queue_basename.'-'.$this->transport());

View File

@ -497,6 +497,22 @@ function common_linkify($url) {
$attrs = array('href' => $longurl, 'rel' => 'external');
$is_attachment = false;
$attachment_id = null;
$has_thumb = false;
// Check to see whether there's a filename associated with this URL.
// If there is, it's an upload and qualifies as an attachment
$localfile = File::staticGet('url', $longurl);
if (!empty($localfile)) {
if (isset($localfile->filename)) {
$is_attachment = true;
$attachment_id = $localfile->id;
}
}
// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID'
// where ID is the id of the attachment for the given URL.
//
@ -504,24 +520,35 @@ function common_linkify($url) {
// we're currently picking up oembeds only.
// I think the best option is another file_view table in the db
// and associated dbobject.
$query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'";
$file = new File;
$file->query($query);
$file->fetch();
if (!empty($file->file_id)) {
$is_attachment = true;
$attachment_id = $file->file_id;
$query = "select file_thumbnail.file_id as file_id from file join file_thumbnail on file.id = file_thumbnail.file_id where file.url='$longurl'";
$file2 = new File;
$file2->query($query);
$file2->fetch();
if (empty($file2->file_id)) {
$attrs['class'] = 'attachment';
} else {
if (!empty($file2)) {
$has_thumb = true;
}
}
// Add clippy
if ($is_attachment) {
$attrs['class'] = 'attachment';
if ($has_thumb) {
$attrs['class'] = 'attachment thumbnail';
}
$attrs['id'] = "attachment-{$file->file_id}";
$attrs['id'] = "attachment-{$attachment_id}";
}
return XMLStringer::estring('a', $attrs, $display);
}
@ -826,89 +853,91 @@ function common_broadcast_notice($notice, $remote=false)
function common_enqueue_notice($notice)
{
$transports = array('omb', 'sms', 'public', 'twitter', 'facebook', 'ping');
if (common_config('xmpp', 'enabled'))
{
$transports[] = 'jabber';
}
if (common_config('queue','subsystem') == 'stomp') {
// use an external message queue system via STOMP
require_once("Stomp.php");
$con = new Stomp(common_config('queue','stomp_server'));
if (!$con->connect()) {
common_log(LOG_ERR, 'Failed to connect to queue server');
return false;
}
$queue_basename = common_config('queue','queue_basename');
foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook', 'ping') as $transport) {
if (!$con->send(
'/queue/'.$queue_basename.'-'.$transport, // QUEUE
$notice->id, // BODY of the message
array ( // HEADERS of the msg
'created' => $notice->created
))) {
common_log(LOG_ERR, 'Error sending to '.$transport.' queue');
return false;
}
common_log(LOG_DEBUG, 'complete remote queueing notice ID = ' . $notice->id . ' for ' . $transport);
}
//send tags as headers, so they can be used as JMS selectors
common_log(LOG_DEBUG, 'searching for tags ' . $notice->id);
$tags = array();
$tag = new Notice_tag();
$tag->notice_id = $notice->id;
if ($tag->find()) {
while ($tag->fetch()) {
common_log(LOG_DEBUG, 'tag found = ' . $tag->tag);
array_push($tags,$tag->tag);
}
}
$tag->free();
$con->send('/topic/laconica.'.$notice->profile_id,
$notice->content,
array(
'profile_id' => $notice->profile_id,
'created' => $notice->created,
'tags' => implode($tags,' - ')
)
);
common_log(LOG_DEBUG, 'sent to personal topic ' . $notice->id);
$con->send('/topic/laconica.allusers',
$notice->content,
array(
'profile_id' => $notice->profile_id,
'created' => $notice->created,
'tags' => implode($tags,' - ')
)
);
common_log(LOG_DEBUG, 'sent to catch-all topic ' . $notice->id);
$result = true;
common_enqueue_notice_stomp($notice, $transports);
}
else {
// in any other case, 'internal'
foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook', 'ping') as $transport) {
$qi = new Queue_item();
$qi->notice_id = $notice->id;
$qi->transport = $transport;
$qi->created = $notice->created;
$result = $qi->insert();
if (!$result) {
$last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
common_log(LOG_ERR, 'DB error inserting queue item: ' . $last_error->message);
return false;
}
common_log(LOG_DEBUG, 'complete queueing notice ID = ' . $notice->id . ' for ' . $transport);
}
common_enqueue_notice_db($notice, $transports);
}
return $result;
}
function common_post_inbox_transports()
function common_enqueue_notice_stomp($notice, $transports)
{
$transports = array('omb', 'sms');
// use an external message queue system via STOMP
require_once("Stomp.php");
if (common_config('xmpp', 'enabled')) {
$transports = array_merge($transports, array('jabber', 'public'));
$server = common_config('queue','stomp_server');
$username = common_config('queue', 'stomp_username');
$password = common_config('queue', 'stomp_password');
$con = new Stomp($server);
if (!$con->connect($username, $password)) {
common_log(LOG_ERR, 'Failed to connect to queue server');
return false;
}
return $transports;
$queue_basename = common_config('queue','queue_basename');
foreach ($transports as $transport) {
$result = $con->send('/queue/'.$queue_basename.'-'.$transport, // QUEUE
$notice->id, // BODY of the message
array ('created' => $notice->created));
if (!$result) {
common_log(LOG_ERR, 'Error sending to '.$transport.' queue');
return false;
}
common_log(LOG_DEBUG, 'complete remote queueing notice ID = ' . $notice->id . ' for ' . $transport);
}
//send tags as headers, so they can be used as JMS selectors
common_log(LOG_DEBUG, 'searching for tags ' . $notice->id);
$tags = array();
$tag = new Notice_tag();
$tag->notice_id = $notice->id;
if ($tag->find()) {
while ($tag->fetch()) {
common_log(LOG_DEBUG, 'tag found = ' . $tag->tag);
array_push($tags,$tag->tag);
}
}
$tag->free();
$con->send('/topic/laconica.'.$notice->profile_id,
$notice->content,
array(
'profile_id' => $notice->profile_id,
'created' => $notice->created,
'tags' => implode($tags,' - ')
)
);
common_log(LOG_DEBUG, 'sent to personal topic ' . $notice->id);
$con->send('/topic/laconica.allusers',
$notice->content,
array(
'profile_id' => $notice->profile_id,
'created' => $notice->created,
'tags' => implode($tags,' - ')
)
);
common_log(LOG_DEBUG, 'sent to catch-all topic ' . $notice->id);
$result = true;
}
function common_enqueue_notice_db($notice, $transports)
{
// in any other case, 'internal'
foreach ($transports as $transport) {
common_enqueue_notice_transport($notice, $transport);
}
}
function common_enqueue_notice_transport($notice, $transport)

View File

@ -22,7 +22,7 @@ if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/queuehandler.php');
/**
* Common superclass for all XMPP-using queue handlers. They all need to
* Common superclass for all XMPP-using queue handlers. They all need to
* service their message queues on idle, and forward any incoming messages
* to the XMPP listener connection. So, we abstract out common code to a
* superclass.
@ -30,12 +30,11 @@ require_once(INSTALLDIR.'/lib/queuehandler.php');
class XmppQueueHandler extends QueueHandler
{
function start()
{
# Low priority; we don't want to receive messages
$this->log(LOG_INFO, "INITIALIZE");
$this->conn = jabber_connect($this->_id);
$this->conn = jabber_connect($this->_id.$this->transport());
if ($this->conn) {
$this->conn->addEventHandler('message', 'forward_message', $this);
$this->conn->addEventHandler('reconnect', 'handle_reconnect', $this);
@ -44,7 +43,7 @@ class XmppQueueHandler extends QueueHandler
}
return !is_null($this->conn);
}
function handle_reconnect(&$pl)
{
$this->conn->processUntil('session_start');
@ -63,7 +62,7 @@ class XmppQueueHandler extends QueueHandler
die($e->getMessage());
}
}
function forward_message(&$pl)
{
if ($pl['type'] != 'chat') {

40
scripts/allsites.php Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env php
<?php
/*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2009, Control Yourself, 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/>.
*/
# Abort if called from a web server
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<ENDOFHELP
allsites.php - list all sites configured for multi-site use
returns the nickname of each site configured for multi-site use
ENDOFHELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
$sn = new Status_network();
if ($sn->find()) {
while ($sn->fetch()) {
print "$sn->nickname\n";
}
}

View File

@ -0,0 +1,21 @@
#!/bin/bash
source /etc/laconica/setup.cfg
export nickname=$1
export database=$nickname$DBBASE
# Create the db
mysqladmin -h $DBHOST -u $ADMIN --password=$ADMINPASS -f drop $database
mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS
delete from status_network where nickname = '$nickname';
ENDOFCOMMANDS
for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
rm -Rf $top/$nickname
done

View File

@ -38,9 +38,6 @@ if(common_config('xmpp','enabled')) {
echo "xmppdaemon.php jabberqueuehandler.php publicqueuehandler.php ";
echo "xmppconfirmhandler.php ";
}
if(common_config('memcached','enabled')) {
echo "memcachedqueuehandler.php ";
}
if(common_config('twitterbridge','enabled')) {
echo "twitterstatusfetcher.php ";
}

View File

@ -20,13 +20,13 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'r::';
$longoptions = array('resource::');
$shortoptions = 'i::';
$longoptions = array('id::');
$helptext = <<<END_OF_JABBER_HELP
Daemon script for pushing new notices to Jabber users.
-r --resource Jabber Resource ID (default to config)
-i --id Identity (default none)
END_OF_JABBER_HELP;
@ -63,16 +63,16 @@ if (common_config('xmpp','enabled')==false) {
exit();
}
if (have_option('r')) {
$resource = get_option_value('r');
} else if (have_option('--resource')) {
$resource = get_option_value('--resource');
if (have_option('i')) {
$id = get_option_value('i');
} else if (have_option('--id')) {
$id = get_option_value('--id');
} else if (count($args) > 0) {
$resource = $args[0];
$id = $args[0];
} else {
$resource = null;
$id = null;
}
$handler = new JabberQueueHandler($resource);
$handler = new JabberQueueHandler($id);
$handler->runOnce();

View File

@ -20,13 +20,13 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'r::';
$longoptions = array('resource::');
$shortoptions = 'i::';
$longoptions = array('id::');
$helptext = <<<END_OF_PUBLIC_HELP
Daemon script for pushing new notices to public XMPP subscribers.
-r --resource Jabber Resource ID
-i --id Identity (default none)
END_OF_PUBLIC_HELP;
@ -61,16 +61,16 @@ if (common_config('xmpp','enabled')==false) {
exit();
}
if (have_option('r')) {
$resource = get_option_value('r');
} else if (have_option('--resource')) {
$resource = get_option_value('--resource');
if (have_option('i')) {
$id = get_option_value('i');
} else if (have_option('--id')) {
$id = get_option_value('--id');
} else if (count($args) > 0) {
$resource = $args[0];
$id = $args[0];
} else {
$resource = null;
$id = null;
}
$handler = new PublicQueueHandler($resource);
$handler = new PublicQueueHandler($id);
$handler->runOnce();

View File

@ -1,13 +1,14 @@
# CONFIGURATION FILE for setup_status_network.sh
# Base database name; full name will include nickname
export DBHOST=masterdb.example.net
export DBHOST=localhost
export DBHOSTNAME=masterdb.example.net
export DBBASE=_example_net
export USERBASE=_example_net
export ADMIN=root
export ADMINPASS=yourpassword
export SITEDB=example_net_site
export AVATARBASE=/var/www/avatar.example.net
export BACKGROUNDBASE=/var/www/background.example.net
export FILEBASE=/var/www/file.example.net
export PWDGEN="pwgen 20"

View File

@ -1,6 +1,6 @@
#!/bin/bash
source ./setup.cfg
source /etc/laconica/setup.cfg
export nickname=$1
export sitename=$2
@ -22,9 +22,11 @@ mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS
GRANT INSERT,SELECT,UPDATE,DELETE ON $database.* TO '$username'@'localhost' IDENTIFIED BY '$password';
GRANT INSERT,SELECT,UPDATE,DELETE ON $database.* TO '$username'@'%' IDENTIFIED BY '$password';
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created)
VALUES ('$nickname', '$DBHOST', '$username', '$password', '$database', '$sitename', now());
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now());
ENDOFCOMMANDS
mkdir $AVATARBASE/$nickname
chmod a+w $AVATARBASE/$nickname
for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
mkdir $top/$nickname
chmod a+w $top/$nickname
done

View File

@ -20,12 +20,27 @@
# This program tries to start the daemons for Laconica.
# Note that the 'maildaemon' needs to run as a mail filter.
ARGSG=
ARGSD=
if [ $# -gt 0 ]; then
ARGSG="$ARGSG -s$1"
ID=`echo $1 | sed s/\\\\./_/g`
ARGSD="$ARGSD -s$1 -i$ID"
fi
if [ $# -gt 1 ]; then
ARGSD="$ARGSD -p$2"
ARGSG="$ARGSG -p$2"
fi
DIR=`dirname $0`
DAEMONS=`php $DIR/getvaliddaemons.php`
DAEMONS=`php $DIR/getvaliddaemons.php $ARGSG`
for f in $DAEMONS; do
echo -n "Starting $f...";
php $DIR/$f
echo "DONE."
printf "Starting $f...";
php $DIR/$f $ARGSD
printf "DONE.\n"
done

View File

@ -20,13 +20,13 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'r::';
$longoptions = array('resource::');
$shortoptions = 'i::';
$longoptions = array('id::');
$helptext = <<<END_OF_JABBER_HELP
Daemon script for pushing new confirmations to Jabber users.
-r --resource Jabber Resource ID (default to config)
-i --id Identity (default none)
END_OF_JABBER_HELP;
@ -147,17 +147,17 @@ if (common_config('xmpp','enabled')==false) {
exit();
}
if (have_option('r')) {
$resource = get_option_value('r');
} else if (have_option('--resource')) {
$resource = get_option_value('--resource');
if (have_option('i')) {
$id = get_option_value('i');
} else if (have_option('--id')) {
$id = get_option_value('--id');
} else if (count($args) > 0) {
$resource = $args[0];
$id = $args[0];
} else {
$resource = null;
$id = null;
}
$handler = new XmppConfirmHandler($resource);
$handler = new XmppConfirmHandler($id);
$handler->runOnce();

View File

@ -20,13 +20,13 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'r::';
$longoptions = array('resource::');
$shortoptions = 'i::';
$longoptions = array('id::');
$helptext = <<<END_OF_XMPP_HELP
Daemon script for receiving new notices from Jabber users.
-r --resource Jabber Resource ID (default to config)
-i --id Identity (default none)
END_OF_XMPP_HELP;
@ -52,7 +52,7 @@ class XMPPDaemon extends Daemon
}
if ($resource) {
$this->resource = $resource;
$this->resource = $resource . 'daemon';
} else {
$this->resource = common_config('xmpp', 'resource') . 'daemon';
}
@ -323,16 +323,16 @@ if (common_config('xmpp','enabled')==false) {
exit();
}
if (have_option('r')) {
$resource = get_option_value('r');
} else if (have_option('--resource')) {
$resource = get_option_value('--resource');
if (have_option('i')) {
$id = get_option_value('i');
} else if (have_option('--id')) {
$id = get_option_value('--id');
} else if (count($args) > 0) {
$resource = $args[0];
$id = $args[0];
} else {
$resource = null;
$id = null;
}
$daemon = new XMPPDaemon($resource);
$daemon = new XMPPDaemon($id);
$daemon->runOnce();

View File

@ -510,13 +510,26 @@ margin-bottom:7px;
margin-left:18px;
float:left;
}
#form_notice .error {
#form_notice .error,
#form_notice .success {
float:left;
clear:both;
width:96.9%;
width:81.5%;
margin-bottom:0;
line-height:1.618;
}
#form_notice #notice_data-attach_selected code {
float:left;
width:90%;
display:block;
font-size:1.1em;
line-height:1.8;
overflow:auto;
}
#form_notice #notice_data-attach_selected button {
float:right;
font-size:0.8em;
}
/* entity_profile */
.entity_profile {
@ -548,7 +561,8 @@ margin-bottom:18px;
.entity_profile .entity_location,
.entity_profile .entity_url,
.entity_profile .entity_note,
.entity_profile .entity_tags {
.entity_profile .entity_tags,
.entity_profile .entity_aliases {
margin-left:113px;
margin-bottom:4px;
}

View File

@ -19,6 +19,12 @@ display:block;
width:17%;
max-width:17%;
}
#form_notice #notice_data-attach_selected {
width:78.5%;
}
#form_notice #notice_data-attach_selected button {
padding:0 4px;
}
#anon_notice {
max-width:39%;
}

View File

@ -11,7 +11,7 @@
body,
a:active {
background-color:#C3D6DF;
background-color:#CEE1E9;
}
body {
font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
@ -29,7 +29,7 @@ input, textarea, select,
border-color:#AAAAAA;
}
#filter_tags ul li {
border-color:#C3D6DF;
border-color:#DDDDDD;
}
.form_settings input.form_action-primary {
@ -40,12 +40,12 @@ input.submit,
#form_notice.warning #notice_text-count,
.form_settings .form_note,
.entity_remote_subscribe {
background-color:#A9BF4F;
background-color:#9BB43E;
}
input:focus, textarea:focus, select:focus,
#form_notice.warning #notice_data-text {
border-color:#A9BF4F;
border-color:#9BB43E;
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
@ -71,14 +71,14 @@ color:#002E6E;
.notice,
.profile {
border-top-color:#D1D9E4;
border-top-color:#C8D1D5;
}
.section .profile {
border-top-color:#C3D6DF;
border-top-color:#87B4C8;
}
#aside_primary {
background-color:#CEE1E9;
background-color:#C8D1D5;
}
#notice_text-count {
@ -136,13 +136,13 @@ background-color:#EFF3DC;
}
#anon_notice {
background-color:#C3D6DF;
background-color:#87B4C8;
color:#FFFFFF;
border-color:#FFFFFF;
}
#showstream #anon_notice {
background-color:#A9BF4F;
background-color:#9BB43E;
}
#export_data li a {
@ -176,13 +176,13 @@ background-color:transparent;
.form_group_leave input.submit
.form_user_subscribe input.submit,
.form_user_unsubscribe input.submit {
background-color:#A9BF4F;
background-color:#9BB43E;
color:#FFFFFF;
}
.form_user_unsubscribe input.submit,
.form_group_leave input.submit,
.form_user_authorization input.reject {
background-color:#C3D6DF;
background-color:#87B4C8;
}
.entity_edit a {
@ -245,7 +245,7 @@ div.notice-options input {
font-family:sans-serif;
}
#content .notices li:hover {
background-color:#FCFCFC;
background-color:rgba(240, 240, 240, 0.2);
}
#conversation .notices li:hover {
background-color:transparent;
@ -272,7 +272,7 @@ background:transparent url(../../base/images/icons/twotone/green/news.gif) no-re
.pagination .nav_prev a,
.pagination .nav_next a {
background-repeat:no-repeat;
border-color:#D1D9E4;
border-color:#C8D1D5;
}
.pagination .nav_prev a {
background-image:url(../../base/images/icons/twotone/green/arrow-left.gif);

View File

@ -1,14 +1,14 @@
/* IE specific styles */
.notice-options input.submit {
color:#fff;
color:#FFFFFF;
}
#site_nav_local_views a {
background-color:#ACCCDA;
background-color:#C8D1D5;
}
#form_notice .form_note + label {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
}
#form_notice #notice_data-attach {
filter: alpha(opacity=0);
}
}

View File

@ -245,7 +245,7 @@ div.notice-options input {
font-family:sans-serif;
}
#content .notices li:hover {
background-color:#FCFCFC;
background-color:rgba(240, 240, 240, 0.2);
}
#conversation .notices li:hover {
background-color:transparent;

View File

@ -1,14 +1,14 @@
/* IE specific styles */
.notice-options input.submit {
color:#fff;
color:#FFFFFF;
}
#site_nav_local_views a {
background-color:#D0DFE7;
background-color:#D9DADB;
}
#form_notice .form_note + label {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
}
#form_notice #notice_data-attach {
filter: alpha(opacity=0);
}
}