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)) { if (empty($this->id)) {
return false; return false;
} }
$this->id = $this->id+0;
$this->page = $this->trimmed('page'); $this->page = $this->trimmed('page');
if (empty($this->page)) { if (empty($this->page)) {
$this->page = 1; $this->page = 1;
@ -106,18 +107,10 @@ class ConversationAction extends Action
function showContent() 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; $offset = ($this->page-1) * NOTICES_PER_PAGE;
$limit = NOTICES_PER_PAGE + 1; $limit = NOTICES_PER_PAGE + 1;
$txt = sprintf($qry, $this->id); $notices = Notice::conversationStream($this->id, $offset, $limit);
$notices = Notice::getStream($txt,
'notice:conversation:'.$this->id,
$offset, $limit);
$ct = new ConversationTree($notices, $this); $ct = new ConversationTree($notices, $this);
@ -126,7 +119,6 @@ class ConversationAction extends Action
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'conversation', array('id' => $this->id)); $this->page, 'conversation', array('id' => $this->id));
} }
} }
/** /**

View File

@ -21,20 +21,40 @@ if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/actions/shownotice.php'); require_once(INSTALLDIR.'/actions/shownotice.php');
class FileAction extends ShowNoticeAction class FileAction extends Action
{ {
function showPage() { var $id = null;
$source_url = common_local_url('file', array('notice' => $this->notice->id)); var $filerec = null;
$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; function prepare($args)
$file->query($query); {
$file->fetch(); parent::prepare($args);
if (empty($file->url)) { $this->id = $this->trimmed('notice');
die('nothing attached here'); if (empty($this->id)) {
} else { $this->clientError(_('No notice id'));
header("Location: {$file->url}");
die();
} }
$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->sidebarcolor = $sbcolor->intValue();
$design->textcolor = $tcolor->intValue(); $design->textcolor = $tcolor->intValue();
$design->linkcolor = $lcolor->intValue(); $design->linkcolor = $lcolor->intValue();
$design->backgroundimage = $filepath;
$design->setDisposition($on, $off, $tile); $design->setDisposition($on, $off, $tile);
@ -263,7 +262,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction
$design->sidebarcolor = $sbcolor->intValue(); $design->sidebarcolor = $sbcolor->intValue();
$design->textcolor = $tcolor->intValue(); $design->textcolor = $tcolor->intValue();
$design->linkcolor = $lcolor->intValue(); $design->linkcolor = $lcolor->intValue();
$design->backgroundimage = $filepath;
$design->setDisposition($on, $off, $tile); $design->setDisposition($on, $off, $tile);

View File

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

View File

@ -35,6 +35,10 @@ require_once INSTALLDIR.'/lib/publicgroupnav.php';
require_once INSTALLDIR.'/lib/noticelist.php'; require_once INSTALLDIR.'/lib/noticelist.php';
require_once INSTALLDIR.'/lib/feedlist.php'; require_once INSTALLDIR.'/lib/feedlist.php';
// Farther than any human will go
define('MAX_PUBLIC_PAGE', 100);
/** /**
* Action for displaying the public stream * Action for displaying the public stream
* *
@ -74,6 +78,10 @@ class PublicAction extends Action
parent::prepare($args); parent::prepare($args);
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; $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()); common_set_returnto($this->selfUrl());
return true; return true;

View File

@ -191,10 +191,21 @@ class ShowfavoritesAction extends CurrentUserDesignAction
function showContent() function showContent()
{ {
$notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE, $cur = common_current_user();
NOTICES_PER_PAGE + 1);
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.')); $this->serverError(_('Could not retrieve favorite notices.'));
return; return;
} }

View File

@ -61,7 +61,11 @@ class TwitapifavoritesAction extends TwitterapiAction
$since_id = (int)$this->arg('since_id', 0); $since_id = (int)$this->arg('since_id', 0);
$since = $this->arg('since'); $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']) { switch($apidata['content-type']) {
case 'xml': case 'xml':

View File

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

View File

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

View File

@ -37,52 +37,62 @@ class Fave extends Memcached_DataObject
return Memcached_DataObject::pkeyGet('Fave', $kv); 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'), $ids = Notice::stream(array('Fave', '_streamDirect'),
array($user_id), array($user_id, $own),
'fave:ids_by_user:'.$user_id, ($own) ? 'fave:ids_by_user_own:'.$user_id :
'fave:by_user:'.$user_id,
$offset, $limit); $offset, $limit);
return $ids; 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(); $fav = new Fave();
$qry = null;
$fav->user_id = $user_id; if ($own) {
$qry = 'SELECT fave.* FROM fave ';
$fav->selectAdd(); $qry .= 'WHERE fave.user_id = ' . $user_id . ' ';
$fav->selectAdd('notice_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) { if ($since_id != 0) {
$fav->whereAdd('notice_id > ' . $since_id); $qry .= 'AND notice_id > ' . $since_id . ' ';
} }
if ($max_id != 0) { if ($max_id != 0) {
$fav->whereAdd('notice_id <= ' . $max_id); $qry .= 'AND notice_id <= ' . $max_id . ' ';
} }
if (!is_null($since)) { 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! // NOTE: we sort by fave time, not by notice time!
$fav->orderBy('modified DESC'); $qry .= 'ORDER BY modified DESC ';
if (!is_null($offset)) { if (!is_null($offset)) {
$fav->limit($offset, $limit); $qry .= "LIMIT $offset, $limit";
} }
$fav->query($qry);
$ids = array(); $ids = array();
if ($fav->find()) { while ($fav->fetch()) {
while ($fav->fetch()) { $ids[] = $fav->notice_id;
$ids[] = $fav->notice_id;
}
} }
$fav->free();
unset($fav);
return $ids; return $ids;
} }
} }

View File

@ -91,9 +91,10 @@ class File extends Memcached_DataObject
$given_url = File_redirection::_canonUrl($given_url); $given_url = File_redirection::_canonUrl($given_url);
if (empty($given_url)) return -1; // error, no url to process if (empty($given_url)) return -1; // error, no url to process
$file = File::staticGet('url', $given_url); $file = File::staticGet('url', $given_url);
if (empty($file->id)) { if (empty($file)) {
$file_redir = File_redirection::staticGet('url', $given_url); $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_data = File_redirection::where($given_url);
$redir_url = $redir_data['url']; $redir_url = $redir_data['url'];
if ($redir_url === $given_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... // let's see if we know this...
$a = File::staticGet('url', $short_url); $a = File::staticGet('url', $short_url);
if (empty($a->id)) {
$b = File_redirection::staticGet('url', $short_url); if (!empty($a)) {
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 {
// this is a direct link to $a->url // this is a direct link to $a->url
$url = $a->url; return $a->url;
} } else {
if (isset($url)) { $b = File_redirection::staticGet('url', $short_url);
return $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); $curlh = File_redirection::_commonCurl($short_url, $redirs);
@ -118,28 +114,22 @@ class File_redirection extends Memcached_DataObject
} }
function makeShort($long_url) { 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 $canon = File_redirection::_canonUrl($long_url);
$short_url = File_redirection::_userMakeShort($long_url, common_current_user());
return $short_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); $short_url = common_shorten_url($long_url);
if ($short_url) { if (!empty($short_url) && $short_url != $long_url) {
$short_url = (string)$short_url; $short_url = (string)$short_url;
// store it // store it
$file = File::staticGet('url', $long_url); $file = File::staticGet('url', $long_url);
@ -162,7 +152,7 @@ class File_redirection extends Memcached_DataObject
} }
return $short_url; return $short_url;
} }
return $long_url; return null;
} }
function _canonUrl($in_url, $default_scheme = 'http://') { 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 * Table Definition for file_to_post
*/ */
class File_to_post extends Memcached_DataObject class File_to_post extends Memcached_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */ /* 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) { function processNew($file_id, $notice_id) {
static $seen = array(); static $seen = array();
if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) { if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) {
$f2p = new File_to_post;
$f2p->file_id = $file_id; $f2p = File_to_post::pkeyGet(array('post_id' => $notice_id,
$f2p->post_id = $notice_id; 'file_id' => $file_id));
$f2p->insert(); 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])) { if (empty($seen[$notice_id])) {
$seen[$notice_id] = array($file_id); $seen[$notice_id] = array($file_id);
} else { } else {
$seen[$notice_id][] = $file_id; $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'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Foreign_user extends Memcached_DataObject class Foreign_user extends Memcached_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */ /* the code below is auto generated do not remove the above tag */
public $__table = 'foreign_user'; // table name 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 $service; // int(4) primary_key not_null
public $uri; // varchar(255) unique_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 $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */ /* Static get */
function staticGet($k,$v=null) function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Foreign_user',$k,$v); }
{ return Memcached_DataObject::staticGet('Foreign_user',$k,$v); }
/* the code above is auto generated do not remove the tag below */ /* the code above is auto generated do not remove the tag below */
###END_AUTOCODE ###END_AUTOCODE
// XXX: This only returns a 1->1 single obj mapping. Change? Or make // XXX: This only returns a 1->1 single obj mapping. Change? Or make
// a getForeignUsers() that returns more than one? --Zach // a getForeignUsers() that returns more than one? --Zach
static function getForeignUser($id, $service) { static function getForeignUser($id, $service) {
$fuser = new Foreign_user(); $fuser = new Foreign_user();
$fuser->whereAdd("service = $service"); $fuser->whereAdd("service = $service");
$fuser->whereAdd("id = $id"); $fuser->whereAdd("id = $id");
$fuser->limit(1); $fuser->limit(1);
if ($fuser->find()) { if ($fuser->find()) {
$fuser->fetch(); $fuser->fetch();
return $fuser; return $fuser;
} }
return null; return null;
} }
function updateKeys(&$orig) function updateKeys(&$orig)
{ {
$parts = array(); $parts = array();
@ -68,5 +67,4 @@ class Foreign_user extends Memcached_DataObject
return $result; return $result;
} }
} }

View File

@ -14,8 +14,14 @@ class Group_inbox extends Memcached_DataObject
public $created; // datetime() not_null public $created; // datetime() not_null
/* Static get */ /* Static get */
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Group_inbox',$k,$v); } 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 */ /* the code above is auto generated do not remove the tag below */
###END_AUTOCODE ###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; 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) function blowCaches($blowLast=false)
{ {
$this->blowSubsCache($blowLast); $this->blowSubsCache($blowLast);
@ -339,6 +353,19 @@ class Notice extends Memcached_DataObject
$this->blowPublicCache($blowLast); $this->blowPublicCache($blowLast);
$this->blowTagCache($blowLast); $this->blowTagCache($blowLast);
$this->blowGroupCache($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) function blowGroupCache($blowLast=false)
@ -471,8 +498,10 @@ class Notice extends Memcached_DataObject
if ($fave->find()) { if ($fave->find()) {
while ($fave->fetch()) { while ($fave->fetch()) {
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id)); $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) { if ($blowLast) {
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id.';last')); $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)) { if (!empty($cache)) {
$notices = array(); $notices = array();
foreach ($ids as $id) { foreach ($ids as $id) {
$notices[] = Notice::staticGet('id', $id); $n = Notice::staticGet('id', $id);
if (!empty($n)) {
$notices[] = $n;
}
} }
return new ArrayWrapper($notices); return new ArrayWrapper($notices);
} else { } else {
@ -744,29 +776,116 @@ class Notice extends Memcached_DataObject
return $ids; 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() function addToInboxes()
{ {
$enabled = common_config('inboxes', 'enabled'); $enabled = common_config('inboxes', 'enabled');
if ($enabled === true || $enabled === 'transitional') { if ($enabled === true || $enabled === 'transitional') {
$inbox = new Notice_inbox();
$UT = common_config('db','type')=='pgsql'?'"user"':'user'; $users = $this->getSubscribedUsers();
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' .
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " . // FIXME: kind of ignoring 'transitional'...
"FROM $UT JOIN subscription ON $UT.id = subscription.subscriber " . // we'll probably stop supporting inboxless mode
'WHERE subscription.subscribed = ' . $this->profile_id . ' ' . // in 0.9.x
'AND NOT EXISTS (SELECT user_id, notice_id ' .
'FROM notice_inbox ' . foreach ($users as $id) {
"WHERE user_id = $UT.id " . $this->addToUserInbox($id, NOTICE_INBOX_SOURCE_SUB);
'AND notice_id = ' . $this->id . ' )';
if ($enabled === 'transitional') {
$qry .= " AND $UT.inboxed = 1";
} }
$inbox->query($qry);
} }
return; 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() function saveGroups()
{ {
$enabled = common_config('inboxes', 'enabled'); $enabled = common_config('inboxes', 'enabled');
@ -805,13 +924,7 @@ class Notice extends Memcached_DataObject
if ($profile->isMember($group)) { if ($profile->isMember($group)) {
$gi = new Group_inbox(); $result = $this->addToGroupInbox($group);
$gi->group_id = $group->id;
$gi->notice_id = $this->id;
$gi->created = common_sql_now();
$result = $gi->insert();
if (!$result) { if (!$result) {
common_log_db_error($gi, 'INSERT', __FILE__); common_log_db_error($gi, 'INSERT', __FILE__);
@ -819,27 +932,37 @@ class Notice extends Memcached_DataObject
// FIXME: do this in an offline daemon // FIXME: do this in an offline daemon
$this->addToGroupInboxes($group); $this->addToGroupMemberInboxes($group);
} }
} }
} }
function addToGroupInboxes($group) function addToGroupInbox($group)
{ {
$inbox = new Notice_inbox(); $gi = Group_inbox::pkeyGet(array('group_id' => $group->id,
$UT = common_config('db','type')=='pgsql'?'"user"':'user'; 'notice_id' => $this->id));
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "', " . NOTICE_INBOX_SOURCE_GROUP . " " . if (empty($gi)) {
"FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " .
'WHERE group_member.group_id = ' . $group->id . ' ' . $gi = new Group_inbox();
'AND NOT EXISTS (SELECT user_id, notice_id ' .
'FROM notice_inbox ' . $gi->group_id = $group->id;
"WHERE user_id = $UT.id " . $gi->notice_id = $this->id;
'AND notice_id = ' . $this->id . ' )'; $gi->created = $this->created;
if ($enabled === 'transitional') {
$qry .= " AND $UT.inboxed = 1"; 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() function saveReplies()

View File

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

View File

@ -289,4 +289,52 @@ class Profile extends Memcached_DataObject
return Avatar::defaultImage($size); 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); return Notice::getStreamByIds($ids);
} }
@ -600,50 +600,16 @@ class User extends Memcached_DataObject
function getSubscriptions($offset=0, $limit=null) function getSubscriptions($offset=0, $limit=null)
{ {
$qry = $profile = $this->getProfile();
'SELECT profile.* ' . assert(!empty($profile));
'FROM profile JOIN subscription ' . return $profile->getSubscriptions($offset, $limit);
'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) function getSubscribers($offset=0, $limit=null)
{ {
$qry = $profile = $this->getProfile();
'SELECT profile.* ' . assert(!empty($profile));
'FROM profile JOIN subscription ' . return $profile->getSubscribers($offset, $limit);
'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;
} }
function getTaggedSubscribers($tag, $offset=0, $limit=null) 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); 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; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table foreign_user ( 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), service int not null comment 'foreign key to service' references foreign_service(id),
uri varchar(255) not null unique key comment 'identifying URI', uri varchar(255) not null unique key comment 'identifying URI',
nickname varchar(255) comment 'nickname on foreign service', nickname varchar(255) comment 'nickname on foreign service',

View File

@ -48,7 +48,14 @@ function handleError($error)
$logmsg .= " : ". $error->getDebugInfo(); $logmsg .= " : ". $error->getDebugInfo();
} }
common_log(LOG_ERR, $logmsg); 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, '. $msg = sprintf(_('The database for %s isn\'t responding correctly, '.
'so the site won\'t work properly. '. 'so the site won\'t work properly. '.
'The site admins probably know about the problem, '. 'The site admins probably know about the problem, '.

View File

@ -89,11 +89,10 @@ $(document).ready(function() {
$('body').css({'background-image':'none'}); $('body').css({'background-image':'none'});
}); });
$('#design_background-image_on').focus(function() { $('#design_background-image_on').focus(function() {
var bis = $('#design_background-image_onoff img')[0].src; $('body').css({'background-image':'url('+$('#design_background-image_onoff img')[0].src+')'});
$('body').css({'background-image':'url('+bis+')'});
}); });
$('#design_background-image_repeat').click(function() { $('#design_background-image_repeat').click(function() {
($(this)[0].checked) ? $('body').css({'background-repeat':'repeat'}) : $('body').css({'background-repeat':'no-repeat'}); ($(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-text").val("");
$("#notice_data-attach").val(""); $("#notice_data-attach").val("");
$('#notice_data-attach_selected').remove();
counter(); counter();
} }
$("#form_notice").removeClass("processing"); $("#form_notice").removeClass("processing");
@ -233,6 +234,7 @@ $(document).ready(function(){
$("#form_notice").each(addAjaxHidden); $("#form_notice").each(addAjaxHidden);
NoticeReply(); NoticeReply();
NoticeAttachments(); NoticeAttachments();
NoticeDataAttach();
}); });
function NoticeReply() { function NoticeReply() {
@ -280,13 +282,13 @@ function NoticeAttachments() {
timeout : 0 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'}); $().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
return false; return false;
}); });
var t; var t;
$("body:not(#shownotice) a.thumbnail").hover( $("body:not(#shownotice) #content .notice a.thumbnail").hover(
function() { function() {
var anchor = $(this); var anchor = $(this);
$("a.thumbnail").children('img').hide(); $("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; $atts = new File;
$att = $atts->getAttachments($this->notice->id); $att = $atts->getAttachments($this->notice->id);
if (empty($att)) return 0; 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->element('dt', null, _('Attachments'));
$this->out->elementStart('dd'); $this->out->elementStart('dd');
$this->out->elementStart('ol', array('class' => 'attachments')); $this->out->elementStart('ol', array('class' => 'attachments'));
@ -249,10 +250,13 @@ class Attachment extends AttachmentListItem
$this->out->elementStart('div', 'entry-title'); $this->out->elementStart('div', 'entry-title');
$this->out->elementStart('a', $this->linkAttr()); $this->out->elementStart('a', $this->linkAttr());
$this->out->element('span', null, $this->linkTitle()); $this->out->element('span', null, $this->linkTitle());
$this->showRepresentation();
$this->out->elementEnd('a'); $this->out->elementEnd('a');
$this->out->elementEnd('div'); $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)) { if (!empty($this->oembed->author_name) || !empty($this->oembed->provider)) {
$this->out->elementStart('div', array('id' => 'oembed_info', $this->out->elementStart('div', array('id' => 'oembed_info',
'class' => 'entry-content')); 'class' => 'entry-content'));

View File

@ -95,9 +95,9 @@ $config =
'server' => $_server, 'server' => $_server,
'theme' => 'default', 'theme' => 'default',
'design' => 'design' =>
array('backgroundcolor' => '#F0F2F5', array('backgroundcolor' => '#CEE1E9',
'contentcolor' => '#FFFFFF', 'contentcolor' => '#FFFFFF',
'sidebarcolor' => '#CEE1E9', 'sidebarcolor' => '#C8D1D5',
'textcolor' => '#000000', 'textcolor' => '#000000',
'linkcolor' => '#002E6E', 'linkcolor' => '#002E6E',
'backgroundimage' => null, 'backgroundimage' => null,
@ -125,7 +125,13 @@ $config =
array('appname' => 'laconica', # for syslog array('appname' => 'laconica', # for syslog
'priority' => 'debug'), # XXX: currently ignored 'priority' => 'debug'), # XXX: currently ignored
'queue' => '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' => 'license' =>
array('url' => 'http://creativecommons.org/licenses/by/3.0/', array('url' => 'http://creativecommons.org/licenses/by/3.0/',
'title' => 'Creative Commons Attribution 3.0', 'title' => 'Creative Commons Attribution 3.0',

View File

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

View File

@ -72,7 +72,8 @@ class ImageFile
break; break;
case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_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; return;
case UPLOAD_ERR_PARTIAL: case UPLOAD_ERR_PARTIAL:
@unlink($_FILES[$param]['tmp_name']); @unlink($_FILES[$param]['tmp_name']);

View File

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

View File

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

View File

@ -497,6 +497,22 @@ function common_linkify($url) {
$attrs = array('href' => $longurl, 'rel' => 'external'); $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' // 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. // 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. // we're currently picking up oembeds only.
// I think the best option is another file_view table in the db // I think the best option is another file_view table in the db
// and associated dbobject. // 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'"; $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 = new File;
$file->query($query); $file->query($query);
$file->fetch(); $file->fetch();
if (!empty($file->file_id)) { 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'"; $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 = new File;
$file2->query($query); $file2->query($query);
$file2->fetch(); $file2->fetch();
if (empty($file2->file_id)) { if (!empty($file2)) {
$attrs['class'] = 'attachment'; $has_thumb = true;
} else { }
}
// Add clippy
if ($is_attachment) {
$attrs['class'] = 'attachment';
if ($has_thumb) {
$attrs['class'] = 'attachment thumbnail'; $attrs['class'] = 'attachment thumbnail';
} }
$attrs['id'] = "attachment-{$file->file_id}"; $attrs['id'] = "attachment-{$attachment_id}";
} }
return XMLStringer::estring('a', $attrs, $display); return XMLStringer::estring('a', $attrs, $display);
} }
@ -826,89 +853,91 @@ function common_broadcast_notice($notice, $remote=false)
function common_enqueue_notice($notice) 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') { if (common_config('queue','subsystem') == 'stomp') {
// use an external message queue system via STOMP common_enqueue_notice_stomp($notice, $transports);
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;
} }
else { else {
// in any other case, 'internal' common_enqueue_notice_db($notice, $transports);
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);
}
} }
return $result; 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')) { $server = common_config('queue','stomp_server');
$transports = array_merge($transports, array('jabber', 'public')); $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) function common_enqueue_notice_transport($notice, $transport)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
source ./setup.cfg source /etc/laconica/setup.cfg
export nickname=$1 export nickname=$1
export sitename=$2 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'@'localhost' IDENTIFIED BY '$password';
GRANT INSERT,SELECT,UPDATE,DELETE ON $database.* TO '$username'@'%' 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) 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 ENDOFCOMMANDS
mkdir $AVATARBASE/$nickname for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
chmod a+w $AVATARBASE/$nickname mkdir $top/$nickname
chmod a+w $top/$nickname
done

View File

@ -20,12 +20,27 @@
# This program tries to start the daemons for Laconica. # This program tries to start the daemons for Laconica.
# Note that the 'maildaemon' needs to run as a mail filter. # 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` DIR=`dirname $0`
DAEMONS=`php $DIR/getvaliddaemons.php` DAEMONS=`php $DIR/getvaliddaemons.php $ARGSG`
for f in $DAEMONS; do for f in $DAEMONS; do
echo -n "Starting $f..."; printf "Starting $f...";
php $DIR/$f php $DIR/$f $ARGSD
echo "DONE." printf "DONE.\n"
done done

View File

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

View File

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

View File

@ -510,13 +510,26 @@ margin-bottom:7px;
margin-left:18px; margin-left:18px;
float:left; float:left;
} }
#form_notice .error { #form_notice .error,
#form_notice .success {
float:left; float:left;
clear:both; clear:both;
width:96.9%; width:81.5%;
margin-bottom:0; margin-bottom:0;
line-height:1.618; 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 */
.entity_profile { .entity_profile {
@ -548,7 +561,8 @@ margin-bottom:18px;
.entity_profile .entity_location, .entity_profile .entity_location,
.entity_profile .entity_url, .entity_profile .entity_url,
.entity_profile .entity_note, .entity_profile .entity_note,
.entity_profile .entity_tags { .entity_profile .entity_tags,
.entity_profile .entity_aliases {
margin-left:113px; margin-left:113px;
margin-bottom:4px; margin-bottom:4px;
} }

View File

@ -19,6 +19,12 @@ display:block;
width:17%; width:17%;
max-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 { #anon_notice {
max-width:39%; max-width:39%;
} }

View File

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

View File

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

View File

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

View File

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