Merge branch '0.9.x' of git://gitorious.org/statusnet/mainline into 0.9.x

This commit is contained in:
Brion Vibber 2009-10-04 16:16:52 -07:00
commit 4462a1c636
62 changed files with 2116 additions and 2139 deletions

View File

@ -87,6 +87,12 @@ StartShowContentBlock: Showing before the content container
EndShowContentBlock: Showing after the content container
- $action: the current action
StartShowAside: Showing before the Aside container
- $action: the current action
EndShowAside: Showing after the Aside container
- $action: the current action
StartNoticeSave: before inserting a notice (good place for content filters)
- $notice: notice being saved (no ID or URI)
@ -277,3 +283,5 @@ StartShowHeadElements: Right after the <head> tag
EndShowHeadElements: Right before the </head> tag; put <script>s here if you need them in <head>
- $action: the current action
CheckSchema: chance to check the schema

8
README
View File

@ -1037,6 +1037,14 @@ utf8: whether to talk to the database in UTF-8 mode. This is the default
with new installations, but older sites may want to turn it off
until they get their databases fixed up. See "UTF-8 database"
above for details.
schemacheck: when to let plugins check the database schema to add
tables or update them. Values can be 'runtime' (default)
or 'script'. 'runtime' can be costly (plugins check the
schema on every hit, adding potentially several db
queries, some quite long), but not everyone knows how to
run a script. If you can, set this to 'script' and run
scripts/checkschema.php whenever you install or upgrade a
plugin.
syslog
------

View File

@ -160,6 +160,7 @@ class ApiAction extends Action
static $bareauth = array('statuses/user_timeline',
'statuses/friends_timeline',
'statuses/home_timeline',
'statuses/friends',
'statuses/replies',
'statuses/mentions',

View File

@ -32,15 +32,45 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/deleteaction.php';
class DeletenoticeAction extends DeleteAction
class DeletenoticeAction extends Action
{
var $error = null;
var $user = null;
var $notice = null;
var $profile = null;
var $user_profile = null;
function prepare($args)
{
parent::prepare($args);
$this->user = common_current_user();
$notice_id = $this->trimmed('notice');
$this->notice = Notice::staticGet($notice_id);
if (!$this->notice) {
common_user_error(_('No such notice.'));
exit;
}
$this->profile = $this->notice->getProfile();
$this->user_profile = $this->user->getProfile();
return true;
}
function handle($args)
{
parent::handle($args);
if (!common_logged_in()) {
common_user_error(_('Not logged in.'));
exit;
} else if ($this->notice->profile_id != $this->user_profile->id &&
!$this->user->hasRight(Right::deleteOthersNotice)) {
common_user_error(_('Can\'t delete this notice.'));
exit;
}
// XXX: Ajax!
if ($_SERVER['REQUEST_METHOD'] == 'POST') {

View File

@ -250,7 +250,6 @@ class EditgroupAction extends GroupDesignAction
$this->group->homepage = $homepage;
$this->group->description = $description;
$this->group->location = $location;
$this->group->created = common_sql_now();
$result = $this->group->update($orig);

173
actions/foafgroup.php Normal file
View File

@ -0,0 +1,173 @@
<?php
/*
* StatusNet the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* 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/>.
*
* @category Mail
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Toby Inkster <mail@tobyinkster.co.uk>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class FoafGroupAction extends Action
{
function isReadOnly($args)
{
return true;
}
function prepare($args)
{
parent::prepare($args);
$nickname_arg = $this->arg('nickname');
if (empty($nickname_arg)) {
$this->clientError(_('No such group.'), 404);
return false;
}
$this->nickname = common_canonical_nickname($nickname_arg);
// Permanent redirect on non-canonical nickname
if ($nickname_arg != $this->nickname) {
common_redirect(common_local_url('foafgroup',
array('nickname' => $this->nickname)),
301);
return false;
}
$this->group = User_group::staticGet('nickname', $this->nickname);
if (!$this->group) {
$this->clientError(_('No such group.'), 404);
return false;
}
common_set_returnto($this->selfUrl());
return true;
}
function handle($args)
{
parent::handle($args);
header('Content-Type: application/rdf+xml');
$this->startXML();
$this->elementStart('rdf:RDF', array('xmlns:rdf' =>
'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'xmlns:dcterms' =>
'http://purl.org/dc/terms/',
'xmlns:sioc' =>
'http://rdfs.org/sioc/ns#',
'xmlns:foaf' =>
'http://xmlns.com/foaf/0.1/',
'xmlns:statusnet' =>
'http://status.net/ont/',
'xmlns' => 'http://xmlns.com/foaf/0.1/'));
$this->showPpd(common_local_url('foafgroup', array('nickname' => $this->nickname)), $this->group->permalink());
$this->elementStart('Group', array('rdf:about' =>
$this->group->permalink()));
if ($this->group->fullname) {
$this->element('name', null, $this->group->fullname);
}
if ($this->group->description) {
$this->element('dcterms:description', null, $this->group->description);
}
if ($this->group->nickname) {
$this->element('dcterms:identifier', null, $this->group->nickname);
$this->element('nick', null, $this->group->nickname);
}
foreach ($this->group->getAliases() as $alias) {
$this->element('nick', null, $alias);
}
if ($this->group->homeUrl()) {
$this->element('weblog', array('rdf:resource' => $this->group->homeUrl()));
}
if ($this->group->homepage) {
$this->element('page', array('rdf:resource' => $this->group->homepage));
}
if ($this->group->homepage_logo) {
$this->element('depiction', array('rdf:resource' => $this->group->homepage_logo));
}
$members = $this->group->getMembers();
$member_details = array();
while ($members->fetch()) {
$member_uri = common_local_url('userbyid', array('id'=>$members->id));
$member_details[$member_uri] = array(
'nickname' => $members->nickname
);
$this->element('member', array('rdf:resource' => $member_uri));
}
$admins = $this->group->getAdmins();
while ($admins->fetch()) {
$admin_uri = common_local_url('userbyid', array('id'=>$admins->id));
$member_details[$admin_uri]['is_admin'] = true;
$this->element('statusnet:groupAdmin', array('rdf:resource' => $admin_uri));
}
$this->elementEnd('Group');
ksort($member_details);
foreach ($member_details as $uri => $details) {
if ($details['is_admin'])
{
$this->elementStart('Agent', array('rdf:about' => $uri));
$this->element('nick', null, $details['nickname']);
$this->elementStart('holdsAccount');
$this->elementStart('sioc:User', array('rdf:about'=>$uri.'#acct'));
$this->elementStart('sioc:has_function');
$this->elementStart('statusnet:GroupAdminRole');
$this->element('sioc:scope', array('rdf:resource' => $this->group->permalink()));
$this->elementEnd('statusnet:GroupAdminRole');
$this->elementEnd('sioc:has_function');
$this->elementEnd('sioc:User');
$this->elementEnd('holdsAccount');
$this->elementEnd('Agent');
}
else
{
$this->element('Agent', array(
'foaf:nick' => $details['nickname'],
'rdf:about' => $uri,
));
}
}
$this->elementEnd('rdf:RDF');
$this->endXML();
}
function showPpd($foaf_url, $person_uri)
{
$this->elementStart('Document', array('rdf:about' => $foaf_url));
$this->element('primaryTopic', array('rdf:resource' => $person_uri));
$this->elementEnd('Document');
}
}

View File

@ -255,13 +255,6 @@ class NewnoticeAction extends Action
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
($replyto == 'false') ? null : $replyto);
if (is_string($notice)) {
if (isset($filename)) {
$this->deleteFile($filename);
}
$this->clientError($notice);
}
if (isset($mimetype)) {
$this->attachFile($notice, $fileRecord);
}

View File

@ -345,6 +345,11 @@ class ShowgroupAction extends GroupDesignAction
'method' => 'timeline',
'argument' => $this->group->nickname.'.atom')),
sprintf(_('Notice feed for %s group (Atom)'),
$this->group->nickname)),
new Feed(Feed::FOAF,
common_local_url('foafgroup',
array('nickname' => $this->group->nickname)),
sprintf(_('FOAF for %s group'),
$this->group->nickname)));
}

View File

@ -297,11 +297,6 @@ class TwitapistatusesAction extends TwitterapiAction
html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'),
$source, 1, $reply_to);
if (is_string($notice)) {
$this->serverError($notice);
return;
}
common_broadcast_notice($notice);
$apidata['api_arg'] = $notice->id;
}

View File

@ -94,7 +94,13 @@ class File extends Memcached_DataObject
$file_redir = File_redirection::staticGet('url', $given_url);
if (empty($file_redir)) {
$redir_data = File_redirection::where($given_url);
if (is_array($redir_data)) {
$redir_url = $redir_data['url'];
} elseif (is_string($redir_data)) {
$redir_url = $redir_data;
} else {
throw new ServerException("Can't process url '$given_url'");
}
// TODO: max field length
if ($redir_url === $given_url || strlen($redir_url) > 255) {
$x = File::saveNew($redir_data, $given_url);

View File

@ -79,6 +79,9 @@ class File_redirection extends Memcached_DataObject
}
}
if(strpos($short_url,'://') === false){
return $short_url;
}
$curlh = File_redirection::_commonCurl($short_url, $redirs);
// Don't include body in output
curl_setopt($curlh, CURLOPT_NOBODY, true);

View File

@ -1,5 +1,5 @@
<?php
/*
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@ -15,9 +15,26 @@
*
* 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/>.
*
* @category Notices
* @package StatusNet
* @author Brenda Wallace <shiny@cpan.org>
* @author Christopher Vollick <psycotica0@gmail.com>
* @author CiaranG <ciaran@ciarang.com>
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@controlezvous.ca>
* @author Gina Haeussge <osd@foosel.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @author Tom Adams <tom@holizz.com>
* @license GNU Affero General Public License http://www.gnu.org/licenses/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/**
* Table Definition for notice
@ -153,30 +170,30 @@ class Notice extends Memcached_DataObject
$final = common_shorten_links($content);
if (Notice::contentTooLong($final)) {
common_log(LOG_INFO, 'Rejecting notice that is too long.');
return _('Problem saving notice. Too long.');
throw new ClientException(_('Problem saving notice. Too long.'));
}
if (!$profile) {
common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
return _('Problem saving notice. Unknown user.');
throw new ClientException(_('Problem saving notice. Unknown user.'));
}
if (common_config('throttle', 'enabled') && !Notice::checkEditThrottle($profile_id)) {
common_log(LOG_WARNING, 'Excessive posting by profile #' . $profile_id . '; throttled.');
return _('Too many notices too fast; take a breather and post again in a few minutes.');
throw new ClientException(_('Too many notices too fast; take a breather '.
'and post again in a few minutes.'));
}
if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) {
common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.');
throw new ClientException(_('Too many duplicate messages too quickly;'.
' take a breather and post again in a few minutes.'));
}
$banned = common_config('profile', 'banned');
if ( in_array($profile_id, $banned) || in_array($profile->nickname, $banned)) {
common_log(LOG_WARNING, "Attempted post from banned user: $profile->nickname (user id = $profile_id).");
return _('You are banned from posting notices on this site.');
throw new ClientException(_('You are banned from posting notices on this site.'));
}
$notice = new Notice();
@ -222,7 +239,7 @@ class Notice extends Memcached_DataObject
if (!$id) {
common_log_db_error($notice, 'INSERT', __FILE__);
return _('Problem saving notice.');
throw new ServerException(_('Problem saving notice.'));
}
// Update ID-dependent columns: URI, conversation
@ -247,7 +264,7 @@ class Notice extends Memcached_DataObject
if ($changed) {
if (!$notice->update($orig)) {
common_log_db_error($notice, 'UPDATE', __FILE__);
return _('Problem saving notice.');
throw new ServerException(_('Problem saving notice.'));
}
}

View File

@ -476,4 +476,79 @@ class Profile extends Memcached_DataObject
$biolimit = self::maxBio();
return ($biolimit > 0 && !empty($bio) && (mb_strlen($bio) > $biolimit));
}
function delete()
{
$this->_deleteNotices();
$this->_deleteSubscriptions();
$this->_deleteMessages();
$this->_deleteTags();
$this->_deleteBlocks();
$related = array('Avatar',
'Reply',
'Group_member',
);
foreach ($related as $cls) {
$inst = new $cls();
$inst->profile_id = $this->id;
$inst->delete();
}
parent::delete();
}
function _deleteNotices()
{
$notice = new Notice();
$notice->profile_id = $this->id;
if ($notice->find()) {
while ($notice->fetch()) {
$other = clone($notice);
$other->delete();
}
}
}
function _deleteSubscriptions()
{
$sub = new Subscription();
$sub->subscriber = $this->id;
$sub->delete();
$subd = new Subscription();
$subd->subscribed = $this->id;
$subd->delete();
}
function _deleteMessages()
{
$msg = new Message();
$msg->from_profile = $this->id;
$msg->delete();
$msg = new Message();
$msg->to_profile = $this->id;
$msg->delete();
}
function _deleteTags()
{
$tag = new Profile_tag();
$tag->tagged = $this->id;
$tag->delete();
}
function _deleteBlocks()
{
$block = new Profile_block();
$block->blocked = $this->id;
$block->delete();
$block = new Group_block();
$block->blocked = $this->id;
$block->delete();
}
}

View File

@ -711,4 +711,77 @@ class User extends Memcached_DataObject
return true;
}
/**
* Does this user have the right to do X?
*
* With our role-based authorization, this is merely a lookup for whether the user
* has a particular role. The implementation currently uses a switch statement
* to determine if the user has the pre-defined role to exercise the right. Future
* implementations may allow per-site roles, and different mappings of roles to rights.
*
* @param $right string Name of the right, usually a constant in class Right
* @return boolean whether the user has the right in question
*/
function hasRight($right)
{
$result = false;
if (Event::handle('UserRightsCheck', array($this, $right, &$result))) {
switch ($right)
{
case Right::deleteOthersNotice:
$result = $this->hasRole('moderator');
break;
default:
$result = false;
break;
}
}
return $result;
}
function delete()
{
$profile = $this->getProfile();
$profile->delete();
$related = array('Fave',
'User_openid',
'Confirm_address',
'Remember_me',
'Foreign_link',
'Invitation',
);
if (common_config('inboxes', 'enabled')) {
$related[] = 'Notice_inbox';
}
foreach ($related as $cls) {
$inst = new $cls();
$inst->user_id = $this->id;
$inst->delete();
}
$this->_deleteTags();
$this->_deleteBlocks();
parent::delete();
}
function _deleteTags()
{
$tag = new Profile_tag();
$tag->tagger = $this->id;
$tag->delete();
}
function _deleteBlocks()
{
$block = new Profile_block();
$block->blocker = $this->id;
$block->delete();
// XXX delete group block? Reset blocker?
}
}

View File

@ -195,18 +195,6 @@ create table nonce (
constraint primary key (consumer_key, ts, nonce)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
/* One-to-many relationship of user to openid_url */
create table user_openid (
canonical varchar(255) primary key comment 'Canonical true URL',
display varchar(255) not null unique key comment 'URL for viewing, may be different from canonical',
user_id integer not null comment 'user owning this URL' references user (id),
created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified',
index user_openid_user_id_idx (user_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
/* These are used by JanRain OpenID library */
create table oid_associations (

View File

@ -61,6 +61,11 @@ function getPath($req)
}
}
/**
* logs and then displays error messages
*
* @return void
*/
function handleError($error)
{
if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) {

View File

@ -1,3 +1,4 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
@ -31,7 +32,7 @@
* @author Sarven Capadisli <csarven@status.net>
* @author Tom Adams <tom@holizz.com>
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @version 0.9
* @version 0.9.x
* @link http://status.net
*/

View File

@ -120,14 +120,16 @@ class Action extends HTMLOutputter // lawsuit
{
// XXX: attributes (profile?)
$this->elementStart('head');
if (Event::handle('StartShowHeadElements', array($this))) {
$this->showTitle();
$this->showShortcutIcon();
$this->showStylesheets();
$this->showScripts();
$this->showOpenSearch();
$this->showFeeds();
$this->showDescription();
$this->extraHead();
Event::handle('EndShowHeadElements', array($this));
}
$this->elementEnd('head');
}
@ -352,6 +354,7 @@ class Action extends HTMLOutputter // lawsuit
Event::handle('EndShowFooter', array($this));
}
$this->elementEnd('div');
$this->showScripts();
$this->elementEnd('body');
}
@ -525,7 +528,10 @@ class Action extends HTMLOutputter // lawsuit
$this->showContentBlock();
Event::handle('EndShowContentBlock', array($this));
}
if (Event::handle('StartShowAside', array($this))) {
$this->showAside();
Event::handle('EndShowAside', array($this));
}
$this->elementEnd('div');
}

View File

@ -46,11 +46,7 @@ require_once INSTALLDIR.'/lib/error.php';
*/
class ClientErrorAction extends ErrorAction
{
function __construct($message='Error', $code=400)
{
parent::__construct($message, $code);
$this->status = array(400 => 'Bad Request',
static $status = array(400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
@ -68,6 +64,10 @@ class ClientErrorAction extends ErrorAction
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed');
function __construct($message='Error', $code=400)
{
parent::__construct($message, $code);
$this->default = 400;
}
@ -91,9 +91,4 @@ class ClientErrorAction extends ErrorAction
$this->showPage();
}
function title()
{
return $this->status[$this->code];
}
}

View File

@ -53,6 +53,7 @@ require_once('DB/DataObject/Cast.php'); # for dates
if (!function_exists('gettext')) {
require_once("php-gettext/gettext.inc");
}
require_once(INSTALLDIR.'/lib/language.php');
// This gets included before the config file, so that admin code and plugins
@ -93,214 +94,17 @@ if (isset($path)) {
null;
}
// default configuration, overwritten in config.php
require_once(INSTALLDIR.'/lib/default.php');
$config =
array('site' =>
array('name' => 'Just another StatusNet microblog',
'server' => $_server,
'theme' => 'default',
'path' => $_path,
'logfile' => null,
'logo' => null,
'logdebug' => false,
'fancy' => false,
'locale_path' => INSTALLDIR.'/locale',
'language' => 'en_US',
'languages' => get_all_languages(),
'email' =>
array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
'broughtby' => null,
'timezone' => 'UTC',
'broughtbyurl' => null,
'closed' => false,
'inviteonly' => false,
'private' => false,
'ssl' => 'never',
'sslserver' => null,
'shorturllength' => 30,
'dupelimit' => 60, # default for same person saying the same thing
'textlimit' => 140,
),
'syslog' =>
array('appname' => 'statusnet', # for syslog
'priority' => 'debug', # XXX: currently ignored
'facility' => LOG_USER),
'queue' =>
array('enabled' => false,
'subsystem' => 'db', # default to database, or 'stomp'
'stomp_server' => null,
'queue_basename' => 'statusnet',
'stomp_username' => null,
'stomp_password' => null,
),
'license' =>
array('url' => 'http://creativecommons.org/licenses/by/3.0/',
'title' => 'Creative Commons Attribution 3.0',
'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'),
'mail' =>
array('backend' => 'mail',
'params' => null),
'nickname' =>
array('blacklist' => array(),
'featured' => array()),
'profile' =>
array('banned' => array(),
'biolimit' => null),
'avatar' =>
array('server' => null,
'dir' => INSTALLDIR . '/avatar/',
'path' => $_path . '/avatar/'),
'background' =>
array('server' => null,
'dir' => INSTALLDIR . '/background/',
'path' => $_path . '/background/'),
'public' =>
array('localonly' => true,
'blacklist' => array(),
'autosource' => array()),
'theme' =>
array('server' => null,
'dir' => null,
'path'=> null),
'throttle' =>
array('enabled' => false, // whether to throttle edits; false by default
'count' => 20, // number of allowed messages in timespan
'timespan' => 600), // timespan for throttling
'xmpp' =>
array('enabled' => false,
'server' => 'INVALID SERVER',
'port' => 5222,
'user' => 'update',
'encryption' => true,
'resource' => 'uniquename',
'password' => 'blahblahblah',
'host' => null, # only set if != server
'debug' => false, # print extra debug info
'public' => array()), # JIDs of users who want to receive the public stream
'invite' =>
array('enabled' => true),
'sphinx' =>
array('enabled' => false,
'server' => 'localhost',
'port' => 3312),
'tag' =>
array('dropoff' => 864000.0),
'popular' =>
array('dropoff' => 864000.0),
'daemon' =>
array('piddir' => '/var/run',
'user' => false,
'group' => false),
'emailpost' =>
array('enabled' => true),
'sms' =>
array('enabled' => true),
'twitter' =>
array('enabled' => true),
'twitterbridge' =>
array('enabled' => false),
'integration' =>
array('source' => 'StatusNet', # source attribute for Twitter
'taguri' => $_server.',2009'), # base for tag URIs
'twitter' =>
array('consumer_key' => null,
'consumer_secret' => null),
'memcached' =>
array('enabled' => false,
'server' => 'localhost',
'base' => null,
'port' => 11211),
'ping' =>
array('notify' => array()),
'inboxes' =>
array('enabled' => true), # on by default for new sites
'newuser' =>
array('default' => null,
'welcome' => null),
'snapshot' =>
array('run' => 'web',
'frequency' => 10000,
'reporturl' => 'http://status.net/stats/report'),
'attachments' =>
array('server' => null,
'dir' => INSTALLDIR . '/file/',
'path' => $_path . '/file/',
'supported' => array('image/png',
'image/jpeg',
'image/gif',
'image/svg+xml',
'audio/mpeg',
'audio/x-speex',
'application/ogg',
'application/pdf',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template',
'application/vnd.oasis.opendocument.chart',
'application/vnd.oasis.opendocument.chart-template',
'application/vnd.oasis.opendocument.image',
'application/vnd.oasis.opendocument.image-template',
'application/vnd.oasis.opendocument.formula',
'application/vnd.oasis.opendocument.formula-template',
'application/vnd.oasis.opendocument.text-master',
'application/vnd.oasis.opendocument.text-web',
'application/x-zip',
'application/zip',
'text/plain',
'video/mpeg',
'video/mp4',
'video/quicktime',
'video/mpeg'),
'file_quota' => 5000000,
'user_quota' => 50000000,
'monthly_quota' => 15000000,
'uploads' => true,
'filecommand' => '/usr/bin/file',
),
'group' =>
array('maxaliases' => 3,
'desclimit' => null),
'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'),
'search' =>
array('type' => 'fulltext'),
'sessions' =>
array('handle' => false, // whether to handle sessions ourselves
'debug' => false), // debugging output for sessions
'design' =>
array('backgroundcolor' => null, // null -> 'use theme default'
'contentcolor' => null,
'sidebarcolor' => null,
'textcolor' => null,
'linkcolor' => null,
'backgroundimage' => null,
'disposition' => null),
'notice' =>
array('contentlimit' => null),
'message' =>
array('contentlimit' => null),
'http' =>
array('client' => 'curl'), // XXX: should this be the default?
);
// Set config values initially to default values
$config = $default;
// default configuration, overwritten in config.php
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
$config['db'] =
array('database' => 'YOU HAVE TO SET THIS IN config.php',
'schema_location' => INSTALLDIR . '/classes',
'class_location' => INSTALLDIR . '/classes',
'require_prefix' => 'classes/',
'class_prefix' => '',
'mirror' => null,
'utf8' => true,
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
'quote_identifiers' => false,
'type' => 'mysql' );
$config['db'] = $default['db'];
// Backward compatibility
@ -428,6 +232,12 @@ require_once INSTALLDIR.'/lib/serverexception.php';
Config::loadSettings();
// XXX: if plugins should check the schema at runtime, do that here.
if ($config['db']['schemacheck'] == 'runtime') {
Event::handle('CheckSchema');
}
// XXX: other formats here
define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);

233
lib/default.php Normal file
View File

@ -0,0 +1,233 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Default settings for core configuration
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category Config
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2008-9 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
$default =
array('site' =>
array('name' => 'Just another StatusNet microblog',
'server' => $_server,
'theme' => 'default',
'path' => $_path,
'logfile' => null,
'logo' => null,
'logdebug' => false,
'fancy' => false,
'locale_path' => INSTALLDIR.'/locale',
'language' => 'en_US',
'languages' => get_all_languages(),
'email' =>
array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
'broughtby' => null,
'timezone' => 'UTC',
'broughtbyurl' => null,
'closed' => false,
'inviteonly' => false,
'private' => false,
'ssl' => 'never',
'sslserver' => null,
'shorturllength' => 30,
'dupelimit' => 60, # default for same person saying the same thing
'textlimit' => 140,
),
'db' =>
array('database' => 'YOU HAVE TO SET THIS IN config.php',
'schema_location' => INSTALLDIR . '/classes',
'class_location' => INSTALLDIR . '/classes',
'require_prefix' => 'classes/',
'class_prefix' => '',
'mirror' => null,
'utf8' => true,
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
'quote_identifiers' => false,
'type' => 'mysql',
'schemacheck' => 'runtime'), // 'runtime' or 'script'
'syslog' =>
array('appname' => 'statusnet', # for syslog
'priority' => 'debug', # XXX: currently ignored
'facility' => LOG_USER),
'queue' =>
array('enabled' => false,
'subsystem' => 'db', # default to database, or 'stomp'
'stomp_server' => null,
'queue_basename' => 'statusnet',
'stomp_username' => null,
'stomp_password' => null,
),
'license' =>
array('url' => 'http://creativecommons.org/licenses/by/3.0/',
'title' => 'Creative Commons Attribution 3.0',
'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'),
'mail' =>
array('backend' => 'mail',
'params' => null),
'nickname' =>
array('blacklist' => array(),
'featured' => array()),
'profile' =>
array('banned' => array(),
'biolimit' => null),
'avatar' =>
array('server' => null,
'dir' => INSTALLDIR . '/avatar/',
'path' => $_path . '/avatar/'),
'background' =>
array('server' => null,
'dir' => INSTALLDIR . '/background/',
'path' => $_path . '/background/'),
'public' =>
array('localonly' => true,
'blacklist' => array(),
'autosource' => array()),
'theme' =>
array('server' => null,
'dir' => null,
'path'=> null),
'throttle' =>
array('enabled' => false, // whether to throttle edits; false by default
'count' => 20, // number of allowed messages in timespan
'timespan' => 600), // timespan for throttling
'xmpp' =>
array('enabled' => false,
'server' => 'INVALID SERVER',
'port' => 5222,
'user' => 'update',
'encryption' => true,
'resource' => 'uniquename',
'password' => 'blahblahblah',
'host' => null, # only set if != server
'debug' => false, # print extra debug info
'public' => array()), # JIDs of users who want to receive the public stream
'invite' =>
array('enabled' => true),
'sphinx' =>
array('enabled' => false,
'server' => 'localhost',
'port' => 3312),
'tag' =>
array('dropoff' => 864000.0),
'popular' =>
array('dropoff' => 864000.0),
'daemon' =>
array('piddir' => '/var/run',
'user' => false,
'group' => false),
'emailpost' =>
array('enabled' => true),
'sms' =>
array('enabled' => true),
'twitter' =>
array('enabled' => true),
'twitterbridge' =>
array('enabled' => false),
'integration' =>
array('source' => 'StatusNet', # source attribute for Twitter
'taguri' => $_server.',2009'), # base for tag URIs
'twitter' =>
array('consumer_key' => null,
'consumer_secret' => null),
'memcached' =>
array('enabled' => false,
'server' => 'localhost',
'base' => null,
'port' => 11211),
'ping' =>
array('notify' => array()),
'inboxes' =>
array('enabled' => true), # on by default for new sites
'newuser' =>
array('default' => null,
'welcome' => null),
'snapshot' =>
array('run' => 'web',
'frequency' => 10000,
'reporturl' => 'http://status.net/stats/report'),
'attachments' =>
array('server' => null,
'dir' => INSTALLDIR . '/file/',
'path' => $_path . '/file/',
'supported' => array('image/png',
'image/jpeg',
'image/gif',
'image/svg+xml',
'audio/mpeg',
'audio/x-speex',
'application/ogg',
'application/pdf',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template',
'application/vnd.oasis.opendocument.chart',
'application/vnd.oasis.opendocument.chart-template',
'application/vnd.oasis.opendocument.image',
'application/vnd.oasis.opendocument.image-template',
'application/vnd.oasis.opendocument.formula',
'application/vnd.oasis.opendocument.formula-template',
'application/vnd.oasis.opendocument.text-master',
'application/vnd.oasis.opendocument.text-web',
'application/x-zip',
'application/zip',
'text/plain',
'video/mpeg',
'video/mp4',
'video/quicktime',
'video/mpeg'),
'file_quota' => 5000000,
'user_quota' => 50000000,
'monthly_quota' => 15000000,
'uploads' => true,
'filecommand' => '/usr/bin/file',
),
'group' =>
array('maxaliases' => 3,
'desclimit' => null),
'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'),
'search' =>
array('type' => 'fulltext'),
'sessions' =>
array('handle' => false, // whether to handle sessions ourselves
'debug' => false), // debugging output for sessions
'design' =>
array('backgroundcolor' => null, // null -> 'use theme default'
'contentcolor' => null,
'sidebarcolor' => null,
'textcolor' => null,
'linkcolor' => null,
'backgroundimage' => null,
'disposition' => null),
'notice' =>
array('contentlimit' => null),
'message' =>
array('contentlimit' => null),
'http' =>
array('client' => 'curl'), // XXX: should this be the default?
);

View File

@ -1,74 +0,0 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Base class for deleting things
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category Personal
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Sarven Capadisli <csarven@status.net>
* @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
class DeleteAction extends Action
{
var $user = null;
var $notice = null;
var $profile = null;
var $user_profile = null;
function prepare($args)
{
parent::prepare($args);
$this->user = common_current_user();
$notice_id = $this->trimmed('notice');
$this->notice = Notice::staticGet($notice_id);
if (!$this->notice) {
common_user_error(_('No such notice.'));
exit;
}
$this->profile = $this->notice->getProfile();
$this->user_profile = $this->user->getProfile();
return true;
}
function handle($args)
{
parent::handle($args);
if (!common_logged_in()) {
common_user_error(_('Not logged in.'));
exit;
} else if ($this->notice->profile_id != $this->user_profile->id) {
common_user_error(_('Can\'t delete this notice.'));
exit;
}
}
}

View File

@ -44,9 +44,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/
class ErrorAction extends Action
{
static $status = array();
var $code = null;
var $message = null;
var $status = null;
var $default = null;
function __construct($message, $code, $output='php://output', $indent=true)
@ -88,9 +89,10 @@ class ErrorAction extends Action
*
* @return page title
*/
function title()
{
return $this->message;
return self::$status[$this->code];
}
function isReadOnly($args)

View File

@ -468,11 +468,11 @@ class FacebookAction extends Action
$replyto = $this->trimmed('inreplyto');
try {
$notice = Notice::saveNew($user->id, $content,
'web', 1, ($replyto == 'false') ? null : $replyto);
if (is_string($notice)) {
$this->showPage($notice);
} catch (Exception $e) {
$this->showPage($e->getMessage());
return;
}

View File

@ -109,11 +109,13 @@ class HTMLOutputter extends XMLOutputter
header('Content-Type: '.$type);
$this->extraHeaders();
if( ! substr($type,0,strlen('text/html'))=='text/html' ){
// Browsers don't like it when <?xml it output for non-xhtml documents
if (preg_match("/.*\/.*xml/", $type)) {
// Required for XML documents
$this->xw->startDocument('1.0', 'UTF-8');
}
$this->xw->writeDTD('html');
$this->xw->writeDTD('html',
'-//W3C//DTD XHTML 1.0 Strict//EN',
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
$language = $this->getLanguage();
@ -425,16 +427,12 @@ class HTMLOutputter extends XMLOutputter
function autofocus($id)
{
$this->elementStart('script', array('type' => 'text/javascript'));
$this->raw('
<!--
$(document).ready(function() {
var el = $("#' . $id . '");
if (el.length) {
el.focus();
}
});
-->
');
$this->raw('/*<![CDATA[*/'.
' $(document).ready(function() {'.
' var el = $("#' . $id . '");'.
' if (el.length) { el.focus(); }'.
' });'.
' /*]]>*/');
$this->elementEnd('script');
}
}

View File

@ -472,7 +472,10 @@ class NoticeListItem extends Widget
function showDeleteLink()
{
$user = common_current_user();
if ($user && $this->notice->profile_id == $user->id) {
if (!empty($user) &&
($this->notice->profile_id == $user->id || $user->hasRight(Right::deleteOthersNotice))) {
$deleteurl = common_local_url('deletenotice',
array('notice' => $this->notice->id));
$this->out->element('a', array('href' => $deleteurl,

View File

@ -156,7 +156,6 @@ class StatusNetOAuthDataStore extends OAuthDataStore
return $this->new_access_token($consumer);
}
/**
* Revoke specified OAuth token
*
@ -363,9 +362,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore
false,
null,
$omb_notice->getIdentifierURI());
if (is_string($notice)) {
throw new Exception($notice);
}
common_broadcast_notice($notice, true);
}

50
lib/right.php Normal file
View File

@ -0,0 +1,50 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Class for user rights
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category Authorization
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/**
* class for rights
*
* Mostly for holding the rights constants
*
* @category Authorization
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class Right
{
const deleteOthersNotice = 'deleteothersnotice';
}

View File

@ -241,6 +241,10 @@ class Router
array('nickname' => '[a-zA-Z0-9]+'));
}
$m->connect('group/:nickname/foaf',
array('action' => 'foafgroup'),
array('nickname' => '[a-zA-Z0-9]+'));
$m->connect('group/:nickname/blocked',
array('action' => 'blockedfromgroup'),
array('nickname' => '[a-zA-Z0-9]+'));

680
lib/schema.php Normal file
View File

@ -0,0 +1,680 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Database schema utilities
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category Database
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
/**
* Class representing the database schema
*
* A class representing the database schema. Can be used to
* manipulate the schema -- especially for plugins and upgrade
* utilities.
*
* @category Database
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class Schema
{
static $_single = null;
protected $conn = null;
/**
* Constructor. Only run once for singleton object.
*/
protected function __construct()
{
// XXX: there should be an easier way to do this.
$user = new User();
$this->conn = $user->getDatabaseConnection();
$user->free();
unset($user);
}
/**
* Main public entry point. Use this to get
* the singleton object.
*
* @return Schema the (single) Schema object
*/
static function get()
{
if (empty(self::$_single)) {
self::$_single = new Schema();
}
return self::$_single;
}
/**
* Returns a TableDef object for the table
* in the schema with the given name.
*
* Throws an exception if the table is not found.
*
* @param string $name Name of the table to get
*
* @return TableDef tabledef for that table.
*/
public function getTableDef($name)
{
$res =& $this->conn->query('DESCRIBE ' . $name);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
$td = new TableDef();
$td->name = $name;
$td->columns = array();
$row = array();
while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) {
$cd = new ColumnDef();
$cd->name = $row['Field'];
$packed = $row['Type'];
if (preg_match('/^(\w+)\((\d+)\)$/', $packed, $match)) {
$cd->type = $match[1];
$cd->size = $match[2];
} else {
$cd->type = $packed;
}
$cd->nullable = ($row['Null'] == 'YES') ? true : false;
$cd->key = $row['Key'];
$cd->default = $row['Default'];
$cd->extra = $row['Extra'];
$td->columns[] = $cd;
}
return $td;
}
/**
* Gets a ColumnDef object for a single column.
*
* Throws an exception if the table is not found.
*
* @param string $table name of the table
* @param string $column name of the column
*
* @return ColumnDef definition of the column or null
* if not found.
*/
public function getColumnDef($table, $column)
{
$td = $this->getTableDef($table);
foreach ($td->columns as $cd) {
if ($cd->name == $column) {
return $cd;
}
}
return null;
}
/**
* Creates a table with the given names and columns.
*
* @param string $name Name of the table
* @param array $columns Array of ColumnDef objects
* for new table.
*
* @return boolean success flag
*/
public function createTable($name, $columns)
{
$uniques = array();
$primary = array();
$indices = array();
$sql = "CREATE TABLE $name (\n";
for ($i = 0; $i < count($columns); $i++) {
$cd =& $columns[$i];
if ($i > 0) {
$sql .= ",\n";
}
$sql .= $this->_columnSql($cd);
switch ($cd->key) {
case 'UNI':
$uniques[] = $cd->name;
break;
case 'PRI':
$primary[] = $cd->name;
break;
case 'MUL':
$indices[] = $cd->name;
break;
}
}
if (count($primary) > 0) { // it really should be...
$sql .= ",\nconstraint primary key (" . implode(',', $primary) . ")";
}
foreach ($uniques as $u) {
$sql .= ",\nunique index {$name}_{$u}_idx ($u)";
}
foreach ($indices as $i) {
$sql .= ",\nindex {$name}_{$i}_idx ($i)";
}
$sql .= "); ";
$res =& $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Drops a table from the schema
*
* Throws an exception if the table is not found.
*
* @param string $name Name of the table to drop
*
* @return boolean success flag
*/
public function dropTable($name)
{
$res =& $this->conn->query("DROP TABLE $name");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Adds an index to a table.
*
* If no name is provided, a name will be made up based
* on the table name and column names.
*
* Throws an exception on database error, esp. if the table
* does not exist.
*
* @param string $table Name of the table
* @param array $columnNames Name of columns to index
* @param string $name (Optional) name of the index
*
* @return boolean success flag
*/
public function createIndex($table, $columnNames, $name=null)
{
if (!is_array($columnNames)) {
$columnNames = array($columnNames);
}
if (empty($name)) {
$name = "$table_".implode("_", $columnNames)."_idx";
}
$res =& $this->conn->query("ALTER TABLE $table ".
"ADD INDEX $name (".
implode(",", $columnNames).")");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Drops a named index from a table.
*
* @param string $table name of the table the index is on.
* @param string $name name of the index
*
* @return boolean success flag
*/
public function dropIndex($table, $name)
{
$res =& $this->conn->query("ALTER TABLE $table DROP INDEX $name");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Adds a column to a table
*
* @param string $table name of the table
* @param ColumnDef $columndef Definition of the new
* column.
*
* @return boolean success flag
*/
public function addColumn($table, $columndef)
{
$sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef);
$res =& $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Modifies a column in the schema.
*
* The name must match an existing column and table.
*
* @param string $table name of the table
* @param ColumnDef $columndef new definition of the column.
*
* @return boolean success flag
*/
public function modifyColumn($table, $columndef)
{
$sql = "ALTER TABLE $table MODIFY COLUMN " .
$this->_columnSql($columndef);
$res =& $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Drops a column from a table
*
* The name must match an existing column.
*
* @param string $table name of the table
* @param string $columnName name of the column to drop
*
* @return boolean success flag
*/
public function dropColumn($table, $columnName)
{
$sql = "ALTER TABLE $table DROP COLUMN $columnName";
$res =& $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Ensures that a table exists with the given
* name and the given column definitions.
*
* If the table does not yet exist, it will
* create the table. If it does exist, it will
* alter the table to match the column definitions.
*
* @param string $tableName name of the table
* @param array $columns array of ColumnDef
* objects for the table
*
* @return boolean success flag
*/
public function ensureTable($tableName, $columns)
{
// XXX: DB engine portability -> toilet
try {
$td = $this->getTableDef($tableName);
} catch (Exception $e) {
if (preg_match('/no such table/', $e->getMessage())) {
return $this->createTable($tableName, $columns);
} else {
throw $e;
}
}
$cur = $this->_names($td->columns);
$new = $this->_names($columns);
$toadd = array_diff($new, $cur);
$todrop = array_diff($cur, $new);
$same = array_intersect($new, $cur);
$tomod = array();
foreach ($same as $m) {
$curCol = $this->_byName($td->columns, $m);
$newCol = $this->_byName($columns, $m);
if (!$newCol->equals($curCol)) {
$tomod[] = $newCol->name;
}
}
if (count($toadd) + count($todrop) + count($tomod) == 0) {
// nothing to do
return true;
}
// For efficiency, we want this all in one
// query, instead of using our methods.
$phrase = array();
foreach ($toadd as $columnName) {
$cd = $this->_byName($columns, $columnName);
$phrase[] = 'ADD COLUMN ' . $this->_columnSql($cd);
}
foreach ($todrop as $columnName) {
$phrase[] = 'DROP COLUMN ' . $columnName;
}
foreach ($tomod as $columnName) {
$cd = $this->_byName($columns, $columnName);
$phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd);
}
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
$res =& $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**
* Returns the array of names from an array of
* ColumnDef objects.
*
* @param array $cds array of ColumnDef objects
*
* @return array strings for name values
*/
private function _names($cds)
{
$names = array();
foreach ($cds as $cd) {
$names[] = $cd->name;
}
return $names;
}
/**
* Get a ColumnDef from an array matching
* name.
*
* @param array $cds Array of ColumnDef objects
* @param string $name Name of the column
*
* @return ColumnDef matching item or null if no match.
*/
private function _byName($cds, $name)
{
foreach ($cds as $cd) {
if ($cd->name == $name) {
return $cd;
}
}
return null;
}
/**
* Return the proper SQL for creating or
* altering a column.
*
* Appropriate for use in CREATE TABLE or
* ALTER TABLE statements.
*
* @param ColumnDef $cd column to create
*
* @return string correct SQL for that column
*/
private function _columnSql($cd)
{
$sql = "{$cd->name} ";
if (!empty($cd->size)) {
$sql .= "{$cd->type}({$cd->size}) ";
} else {
$sql .= "{$cd->type} ";
}
if (!empty($cd->default)) {
$sql .= "default {$cd->default} ";
} else {
$sql .= ($cd->nullable) ? "null " : "not null ";
}
return $sql;
}
}
/**
* A class encapsulating the structure of a table.
*
* @category Database
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class TableDef
{
/** name of the table */
public $name;
/** array of ColumnDef objects for the columns. */
public $columns;
}
/**
* A class encapsulating the structure of a column in a table.
*
* @category Database
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ColumnDef
{
/** name of the column. */
public $name;
/** type of column, e.g. 'int', 'varchar' */
public $type;
/** size of the column. */
public $size;
/** boolean flag; can it be null? */
public $nullable;
/**
* type of key: null = no key; 'PRI' => primary;
* 'UNI' => unique key; 'MUL' => multiple values.
*/
public $key;
/** default value if any. */
public $default;
/** 'extra' stuff. Returned by MySQL, largely
* unused. */
public $extra;
/**
* Constructor.
*
* @param string $name name of the column
* @param string $type type of the column
* @param int $size size of the column
* @param boolean $nullable can this be null?
* @param string $key type of key
* @param value $default default value
* @param value $extra unused
*/
function __construct($name=null, $type=null, $size=null,
$nullable=true, $key=null, $default=null,
$extra=null)
{
$this->name = strtolower($name);
$this->type = strtolower($type);
$this->size = $size+0;
$this->nullable = $nullable;
$this->key = $key;
$this->default = $default;
$this->extra = $extra;
}
/**
* Compares this columndef with another to see
* if they're functionally equivalent.
*
* @param ColumnDef $other column to compare
*
* @return boolean true if equivalent, otherwise false.
*/
function equals($other)
{
return ($this->name == $other->name &&
$this->_typeMatch($other) &&
$this->_defaultMatch($other) &&
$this->_nullMatch($other) &&
$this->key == $other->key);
}
/**
* Does the type of this column match the
* type of the other column?
*
* Checks the type and size of a column. Tries
* to ignore differences between synonymous
* data types, like 'integer' and 'int'.
*
* @param ColumnDef $other other column to check
*
* @return boolean true if they're about equivalent
*/
private function _typeMatch($other)
{
switch ($this->type) {
case 'integer':
case 'int':
return ($other->type == 'integer' ||
$other->type == 'int');
break;
default:
return ($this->type == $other->type &&
$this->size == $other->size);
}
}
/**
* Does the default behaviour of this column match
* the other?
*
* @param ColumnDef $other other column to check
*
* @return boolean true if defaults are effectively the same.
*/
private function _defaultMatch($other)
{
return ((is_null($this->default) && is_null($other->default)) ||
($this->default == $other->default));
}
/**
* Does the null behaviour of this column match
* the other?
*
* @param ColumnDef $other other column to check
*
* @return boolean true if these columns 'null' the same.
*/
private function _nullMatch($other)
{
return ((!is_null($this->default) && !is_null($other->default) &&
$this->default == $other->default) ||
($this->nullable == $other->nullable));
}
}

View File

@ -55,17 +55,17 @@ require_once INSTALLDIR.'/lib/error.php';
class ServerErrorAction extends ErrorAction
{
function __construct($message='Error', $code=500)
{
parent::__construct($message, $code);
$this->status = array(500 => 'Internal Server Error',
static $status = array(500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported');
function __construct($message='Error', $code=500)
{
parent::__construct($message, $code);
$this->default = 500;
// Server errors must be logged.
@ -93,9 +93,4 @@ class ServerErrorAction extends ErrorAction
$this->showPage();
}
function title()
{
return $this->status[$this->code];
}
}

View File

@ -936,35 +936,16 @@ class TwitterapiAction extends Action
function clientError($msg, $code = 400, $content_type = 'json')
{
static $status = array(400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed');
$action = $this->trimmed('action');
common_debug("User error '$code' on '$action': $msg", __FILE__);
if (!array_key_exists($code, $status)) {
if (!array_key_exists($code, ClientErrorAction::$status)) {
$code = 400;
}
$status_string = $status[$code];
$status_string = ClientErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string);
if ($content_type == 'xml') {
@ -983,6 +964,35 @@ class TwitterapiAction extends Action
}
function serverError($msg, $code = 500, $content_type = 'json')
{
$action = $this->trimmed('action');
common_debug("Server error '$code' on '$action': $msg", __FILE__);
if (!array_key_exists($code, ServerErrorAction::$status)) {
$code = 400;
}
$status_string = ServerErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string);
if ($content_type == 'xml') {
$this->init_document('xml');
$this->elementStart('hash');
$this->element('error', null, $msg);
$this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash');
$this->end_document('xml');
} else {
$this->init_document('json');
$error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array));
$this->end_document('json');
}
}
function init_twitter_rss()
{
$this->startXML();

View File

@ -522,12 +522,13 @@ function common_linkify($url) {
if(strpos($url, '@') !== false && strpos($url, ':') === false) {
//url is an email address without the mailto: protocol
return XMLStringer::estring('a', array('href' => "mailto:$url", 'rel' => 'external'), $url);
}
$canon = "mailto:$url";
$longurl = "mailto:$url";
}else{
$canon = File_redirection::_canonUrl($url);
$longurl_data = File_redirection::where($url);
$longurl_data = File_redirection::where($canon);
if (is_array($longurl_data)) {
$longurl = $longurl_data['url'];
} elseif (is_string($longurl_data)) {
@ -535,7 +536,7 @@ function common_linkify($url) {
} else {
throw new ServerException("Can't linkify url '$url'");
}
}
$attrs = array('href' => $canon, 'title' => $longurl, 'rel' => 'external');
$is_attachment = false;

View File

@ -222,4 +222,19 @@ class OpenIDPlugin extends Plugin
return true;
}
function onCheckSchema() {
$schema = Schema::get();
$schema->ensureTable('user_openid',
array(new ColumnDef('canonical', 'varchar',
'255', false, 'PRI'),
new ColumnDef('display', 'varchar',
'255', false),
new ColumnDef('user_id', 'integer',
null, false, 'MUL'),
new ColumnDef('created', 'datetime',
null, false),
new ColumnDef('modified', 'timestamp')));
return true;
}
}

View File

@ -0,0 +1,154 @@
<?php
/**
* Laconica, the distributed open-source microblogging tool
*
* Plugin to do "real time" updates using Orbited + STOMP
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category Plugin
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @copyright 2009 Control Yourself, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
if (!defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php';
/**
* Plugin to do realtime updates using Orbited + STOMP
*
* This plugin pushes data to a STOMP server which is then served to the
* browser by the Orbited server.
*
* @category Plugin
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
class OrbitedPlugin extends RealtimePlugin
{
public $webserver = null;
public $webport = null;
public $channelbase = null;
public $stompserver = null;
public $stompport = null;
public $username = null;
public $password = null;
public $webuser = null;
public $webpass = null;
protected $con = null;
function onStartShowHeadElements($action)
{
// See http://orbited.org/wiki/Deployment#Cross-SubdomainDeployment
$action->element('script', null, ' document.domain = document.domain; ');
}
function _getScripts()
{
$scripts = parent::_getScripts();
$port = (is_null($this->webport)) ? 8000 : $this->webport;
$server = (is_null($this->webserver)) ? common_config('site', 'server') : $this->webserver;
$root = 'http://'.$server.(($port == 80) ? '':':'.$port);
$scripts[] = $root.'/static/Orbited.js';
$scripts[] = common_path('plugins/Orbited/orbitedextra.js');
$scripts[] = $root.'/static/protocols/stomp/stomp.js';
$scripts[] = common_path('plugins/Orbited/orbitedupdater.js');
return $scripts;
}
function _updateInitialize($timeline, $user_id)
{
$script = parent::_updateInitialize($timeline, $user_id);
$server = $this->_getStompServer();
$port = $this->_getStompPort();
return $script." OrbitedUpdater.init(\"$server\", $port, ".
"\"{$timeline}\", \"{$this->webuser}\", \"{$this->webpass}\");";
}
function _connect()
{
require_once(INSTALLDIR.'/extlib/Stomp.php');
$url = $this->_getStompUrl();
$this->con = new Stomp($url);
if ($this->con->connect($this->username, $this->password)) {
$this->log(LOG_INFO, "Connected.");
} else {
$this->log(LOG_ERR, 'Failed to connect to queue server');
throw new ServerException('Failed to connect to queue server');
}
}
function _publish($channel, $message)
{
$result = $this->con->send($channel,
json_encode($message));
return $result;
// TODO: parse and deal with result
}
function _disconnect()
{
$this->con->disconnect();
}
function _pathToChannel($path)
{
if (!empty($this->channelbase)) {
array_unshift($path, $this->channelbase);
}
return '/' . implode('/', $path);
}
function _getStompServer()
{
return (!is_null($this->stompserver)) ? $this->stompserver :
(!is_null($this->webserver)) ? $this->webserver :
common_config('site', 'server');
}
function _getStompPort()
{
return (!is_null($this->stompport)) ? $this->stompport : 61613;
}
function _getStompUrl()
{
$server = $this->_getStompServer();
$port = $this->_getStompPort();
return "tcp://$server:$port/";
}
}

View File

@ -0,0 +1,2 @@
TCPSocket = Orbited.TCPSocket;

View File

@ -0,0 +1,24 @@
// Update the local timeline from a Orbited server
var OrbitedUpdater = function()
{
return {
init: function(server, port, timeline, username, password)
{
// set up stomp client.
stomp = new STOMPClient();
stomp.onmessageframe = function(frame) {
RealtimeUpdate.receive(JSON.parse(frame.body));
};
stomp.onconnectedframe = function() {
stomp.subscribe(timeline);
}
stomp.connect(server, port, username, password);
}
}
}();

View File

@ -38,22 +38,16 @@ if (!defined('STATUSNET')) {
* This plugin will spoot out the correct JavaScript spell to invoke
* Piwik Analytics on a page.
*
* To use this plugin please add the following three lines to your config.php
* To use this plugin add the following to your config.php
*
* require_once('plugins/PiwikAnalyticsPlugin.php');
* $pa = new PiwikAnalyticsPlugin("example.com/piwik/","id");
* addPlugin('PiwikAnalytics', array('piwikroot' => 'example.com/piwik/',
* 'piwikId' => 'id'));
*
* exchange example.com/piwik/ with the url to your piwik installation and
* make sure you don't forget the final /
* exchange id with the ID your statusnet installation has in your Piwik analytics
* Replace 'example.com/piwik/' with the URL to your Piwik installation and
* make sure you don't forget the final /.
* Replace 'id' with the ID your statusnet installation has in your Piwik
* analytics setup - for example '8'.
*
* @category Plugin
* @package StatusNet
* @author Tobias Diekershoff <tobias.diekershoff@gmx.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
* @see Event
*/
class PiwikAnalyticsPlugin extends Plugin

View File

@ -216,8 +216,6 @@ class RealtimePlugin extends Plugin
'class' => 'user_in')
: array('id' => $action->trimmed('action')));
$action->elementStart('div', array('id' => 'header'));
// XXX hack to deal with JS that tries to get the
// root url from page output
@ -230,9 +228,9 @@ class RealtimePlugin extends Plugin
if (common_logged_in()) {
$action->showNoticeForm();
}
$action->elementEnd('div');
$action->showContentBlock();
$action->showScripts();
$action->elementEnd('body');
return false; // No default processing
}

View File

@ -1,72 +0,0 @@
/* Copyright (c) 2006-2007 Mathias Bank (http://www.mathias-bank.de)
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version 2.1
*
* Thanks to
* Hinnerk Ruemenapf - http://hinnerk.ruemenapf.de/ for bug reporting and fixing.
* Tom Leonard for some improvements
*
*/
jQuery.fn.extend({
/**
* Returns get parameters.
*
* If the desired param does not exist, null will be returned
*
* To get the document params:
* @example value = $(document).getUrlParam("paramName");
*
* To get the params of a html-attribut (uses src attribute)
* @example value = $('#imgLink').getUrlParam("paramName");
*/
getUrlParam: function(strParamName){
strParamName = escape(unescape(strParamName));
var returnVal = new Array();
var qString = null;
if ($(this).attr("nodeName")=="#document") {
//document-handler
if (window.location.search.search(strParamName) > -1 ){
qString = window.location.search.substr(1,window.location.search.length).split("&");
}
} else if ($(this).attr("src")!="undefined") {
var strHref = $(this).attr("src")
if ( strHref.indexOf("?") > -1 ){
var strQueryString = strHref.substr(strHref.indexOf("?")+1);
qString = strQueryString.split("&");
}
} else if ($(this).attr("href")!="undefined") {
var strHref = $(this).attr("href")
if ( strHref.indexOf("?") > -1 ){
var strQueryString = strHref.substr(strHref.indexOf("?")+1);
qString = strQueryString.split("&");
}
} else {
return null;
}
if (qString==null) return null;
for (var i=0;i<qString.length; i++){
if (escape(unescape(qString[i].split("=")[0])) == strParamName){
returnVal.push(qString[i].split("=")[1]);
}
}
if (returnVal.length==0) return null;
else if (returnVal.length==1) return returnVal[0];
else return returnVal;
}
});

View File

@ -14,23 +14,36 @@ RealtimeUpdate = {
RealtimeUpdate._replyurl = replyurl;
RealtimeUpdate._favorurl = favorurl;
RealtimeUpdate._deleteurl = deleteurl;
$(window).blur(function() {
$('#notices_primary .notice').css({
'border-top-color':$('#notices_primary .notice:last').css('border-top-color'),
'border-top-style':'dotted'
});
$('#notices_primary .notice:first').css({
'border-top-color':'#AAAAAA',
'border-top-style':'solid'
});
});
},
receive: function(data)
{
setTimeout(function() {
id = data.id;
// Don't add it if it already exists
//
if ($("#notice-"+id).length > 0) {
return;
}
var noticeItem = RealtimeUpdate.makeNoticeItem(data);
$("#notices_primary .notices").prepend(noticeItem, true);
$("#notices_primary .notices").prepend(noticeItem);
$("#notices_primary .notice:first").css({display:"none"});
$("#notices_primary .notice:first").fadeIn(1000);
NoticeReply();
}, 500);
},
makeNoticeItem: function(data)
@ -113,19 +126,22 @@ RealtimeUpdate = {
addPopup: function(url, timeline, iconurl)
{
$('#site_nav_local_views .current a').append('<button id="realtime_timeline" title="Real-time pop window">&#8599;</button>');
$('#notices_primary').css({'position':'relative'});
$('#notices_primary').prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');
$('#realtime_timeline').css({
'margin':'2px 0 0 11px',
'background':'transparent url('+ iconurl + ') no-repeat 45% 45%',
'text-indent':'-9999px',
'width':'16px',
'height':'16px',
'padding':'0',
'margin':'0 0 11px 0',
'background':'transparent url('+ iconurl + ') no-repeat 0% 30%',
'padding':'0 0 0 20px',
'display':'block',
'float':'right',
'position':'absolute',
'top':'-20px',
'right':'0',
'border':'none',
'cursor':'pointer'
'cursor':'pointer',
'color':$("a").css("color"),
'font-weight':'bold',
'font-size':'1em'
});
$('#realtime_timeline').click(function() {
@ -139,9 +155,26 @@ RealtimeUpdate = {
initPopupWindow: function()
{
window.resizeTo(575, 640);
window.resizeTo(500, 550);
$('address').hide();
$('#content').css({'width':'92%'});
$('#content').css({'width':'93.5%'});
$('#form_notice').css({
'margin':'18px 0 18px 1.795%',
'width':'93%',
'max-width':'451px'
});
$('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});
$('.notices li:first-child').css({'border-top-color':'transparent'});
$('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});
$('#form_notice #notice_data-attach').css({
'left':'auto',
'right':'0'
});
}
}

30
scripts/checkschema.php Normal file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<END_OF_CHECKSCHEMA_HELP
Gives plugins a chance to update the database schema.
END_OF_CHECKSCHEMA_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
Event::handle('CheckSchema');

View File

@ -101,7 +101,7 @@ function newSub($i)
$to = User::staticGet('nickname', $tunic);
if (empty($from)) {
if (empty($to)) {
throw new Exception("Can't find user '$tunic'.");
}

68
scripts/deleteuser.php Normal file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'i::n::y';
$longoptions = array('id::nickname::yes');
$helptext = <<<END_OF_DELETEUSER_HELP
deleteuser.php [options]
deletes a user from the database
-i --id ID of the user
-n --nickname nickname of the user
-y --yes do not wait for confirmation
END_OF_DELETEUSER_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
if (have_option('i', 'id')) {
$id = get_option_value('i', 'id');
$user = User::staticGet('id', $id);
if (empty($user)) {
print "Can't find user with ID $id\n";
exit(1);
}
} else if (have_option('n', 'nickname')) {
$nickname = get_option_value('n', 'nickname');
$user = User::staticGet('nickname', $nickname);
if (empty($user)) {
print "Can't find user with nickname '$nickname'\n";
exit(1);
}
} else {
print "You must provide either an ID or a nickname.\n";
exit(1);
}
if (!have_option('y', 'yes')) {
print "About to PERMANENTLY delete user '{$user->nickname}' ({$user->id}). Are you sure? [y/N] ";
$response = fgets(STDIN);
if (strtolower(trim($response)) != 'y') {
print "Aborting.\n";
exit(0);
}
}
print "Deleting...";
$user->delete();
print "DONE.\n";

View File

@ -260,10 +260,11 @@ class MailerDaemon
function add_notice($user, $msg, $fileRecords)
{
try {
$notice = Notice::saveNew($user->id, $msg, 'mail');
if (is_string($notice)) {
$this->log(LOG_ERR, $notice);
return $notice;
} catch (Exception $e) {
$this->log(LOG_ERR, $e->getMessage());
return $e->getMessage();
}
foreach($fileRecords as $fileRecord){
$this->attachFile($notice, $fileRecord);

41
scripts/showtable.php Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<END_OF_SHOWTABLE_HELP
showtable.php <tablename>
Shows the structure of a table
END_OF_SHOWTABLE_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
if (count($args) != 1) {
show_help();
}
$name = $args[0];
$schema = Schema::get();
$td = $schema->getTableDef($name);
print_r($td);

View File

@ -323,12 +323,15 @@ class XMPPDaemon extends Daemon
mb_strlen($content_shortened)));
return;
}
try {
$notice = Notice::saveNew($user->id, $content_shortened, 'xmpp');
if (is_string($notice)) {
$this->log(LOG_ERR, $notice);
$this->from_site($user->jabber, $notice);
} catch (Exception $e) {
$this->log(LOG_ERR, $e->getMessage());
$this->from_site($user->jabber, $e->getMessage());
return;
}
common_broadcast_notice($notice);
$this->log(LOG_INFO,
'Added notice ' . $notice->id . ' from user ' . $user->nickname);

View File

@ -7,6 +7,7 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('STATUSNET', true);
define('LACONICA', true);
require_once INSTALLDIR . '/lib/common.php';

View File

@ -7,6 +7,7 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('STATUSNET', true);
define('LACONICA', true);
require_once INSTALLDIR . '/lib/common.php';
@ -28,69 +29,71 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
array('not a link :: no way',
'not a link :: no way'),
array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link',
'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" title="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
array('http://127.0.0.1',
'<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
'<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
array('127.0.0.1',
'<a href="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
'<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
array('127.0.0.1:99',
'<a href="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
'<a href="http://127.0.0.1:99/" title="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
array('127.0.0.1/Name:test.php',
'<a href="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
'<a href="http://127.0.0.1/Name:test.php" title="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
array('127.0.0.1/~test',
'<a href="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
'<a href="http://127.0.0.1/~test" title="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
array('127.0.0.1/+test',
'<a href="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'),
'<a href="http://127.0.0.1/+test" title="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'),
array('127.0.0.1/$test',
'<a href="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'),
'<a href="http://127.0.0.1/$test" title="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'),
array('127.0.0.1/\'test',
'<a href="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
'<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
array('127.0.0.1/"test',
'<a href="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
'<a href="http://127.0.0.1/&quot;test" title="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
array('127.0.0.1/-test',
'<a href="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
'<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
array('127.0.0.1/_test',
'<a href="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'),
'<a href="http://127.0.0.1/_test" title="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'),
array('127.0.0.1/!test',
'<a href="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'),
'<a href="http://127.0.0.1/!test" title="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'),
array('127.0.0.1/*test',
'<a href="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'),
'<a href="http://127.0.0.1/*test" title="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'),
array('127.0.0.1/test%20stuff',
'<a href="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
'<a href="http://127.0.0.1/test%20stuff" title="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
array('http://[::1]:99/test.php',
'<a href="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
'<a href="http://[::1]:99/test.php" title="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
array('http://::1/test.php',
'<a href="http://::1/test.php" rel="external">http://::1/test.php</a>'),
'<a href="http://::1/test.php" title="http://::1/test.php" rel="external">http://::1/test.php</a>'),
array('http://::1',
'<a href="http://::1/" rel="external">http://::1</a>'),
'<a href="http://::1/" title="http://::1/" rel="external">http://::1</a>'),
array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php',
'<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'),
'<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'),
array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php',
'<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'),
'<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" title="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'),
array('2001:4978:1b5:0:21d:e0ff:fe66:59ab',
'<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'),
'<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'),
array('http://127.0.0.1',
'<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
'<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
array('example.com',
'<a href="http://example.com/" rel="external">example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
array('example.com',
'<a href="http://example.com/" rel="external">example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
array('http://example.com',
'<a href="http://example.com/" rel="external">http://example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
array('http://example.com.',
'<a href="http://example.com/" rel="external">http://example.com</a>.'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'),
array('/var/lib/example.so',
'/var/lib/example.so'),
array('example',
'example'),
array('user@example.com',
'<a href="mailto:user@example.com" rel="external">user@example.com</a>'),
'<a href="mailto:user@example.com" title="mailto:user@example.com" rel="external">user@example.com</a>'),
array('user_name+other@example.com',
'<a href="mailto:user_name+other@example.com" rel="external">user_name+other@example.com</a>'),
'<a href="mailto:user_name+other@example.com" title="mailto:user_name+other@example.com" rel="external">user_name+other@example.com</a>'),
array('mailto:user@example.com',
'<a href="mailto:user@example.com" rel="external">mailto:user@example.com</a>'),
'<a href="mailto:user@example.com" title="mailto:user@example.com" rel="external">mailto:user@example.com</a>'),
array('mailto:user@example.com?subject=test',
'<a href="mailto:user@example.com?subject=test" rel="external">mailto:user@example.com?subject=test</a>'),
'<a href="mailto:user@example.com?subject=test" title="mailto:user@example.com?subject=test" rel="external">mailto:user@example.com?subject=test</a>'),
array('xmpp:user@example.com',
'<a href="xmpp:user@example.com" title="xmpp:user@example.com" rel="external">xmpp:user@example.com</a>'),
array('#example',
'#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example'))) . '" rel="tag">example</a></span>'),
array('#example.com',
@ -98,165 +101,165 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
array('#.net',
'#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('.net'))) . '" rel="tag">.net</a></span>'),
array('http://example',
'<a href="http://example/" rel="external">http://example</a>'),
'<a href="http://example/" title="http://example/" rel="external">http://example</a>'),
array('http://3xampl3',
'<a href="http://3xampl3/" rel="external">http://3xampl3</a>'),
'<a href="http://3xampl3/" title="http://3xampl3/" rel="external">http://3xampl3</a>'),
array('http://example/',
'<a href="http://example/" rel="external">http://example/</a>'),
'<a href="http://example/" title="http://example/" rel="external">http://example/</a>'),
array('http://example/path',
'<a href="http://example/path" rel="external">http://example/path</a>'),
'<a href="http://example/path" title="http://example/path" rel="external">http://example/path</a>'),
array('http://example.com',
'<a href="http://example.com/" rel="external">http://example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
array('https://example.com',
'<a href="https://example.com/" rel="external">https://example.com</a>'),
'<a href="https://example.com/" title="https://example.com/" rel="external">https://example.com</a>'),
array('ftp://example.com',
'<a href="ftp://example.com/" rel="external">ftp://example.com</a>'),
'<a href="ftp://example.com/" title="ftp://example.com/" rel="external">ftp://example.com</a>'),
array('ftps://example.com',
'<a href="ftps://example.com/" rel="external">ftps://example.com</a>'),
'<a href="ftps://example.com/" title="ftps://example.com/" rel="external">ftps://example.com</a>'),
array('http://user@example.com',
'<a href="http://user@example.com/" rel="external">http://user@example.com</a>'),
'<a href="http://user@example.com/" title="http://user@example.com/" rel="external">http://user@example.com</a>'),
array('http://user:pass@example.com',
'<a href="http://user:pass@example.com/" rel="external">http://user:pass@example.com</a>'),
'<a href="http://user:pass@example.com/" title="http://user:pass@example.com/" rel="external">http://user:pass@example.com</a>'),
array('http://example.com:8080',
'<a href="http://example.com:8080/" rel="external">http://example.com:8080</a>'),
'<a href="http://example.com:8080/" title="http://example.com:8080/" rel="external">http://example.com:8080</a>'),
array('http://example.com:8080/test.php',
'<a href="http://example.com:8080/test.php" rel="external">http://example.com:8080/test.php</a>'),
'<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="external">http://example.com:8080/test.php</a>'),
array('example.com:8080/test.php',
'<a href="http://example.com:8080/test.php" rel="external">example.com:8080/test.php</a>'),
'<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="external">example.com:8080/test.php</a>'),
array('http://www.example.com',
'<a href="http://www.example.com/" rel="external">http://www.example.com</a>'),
'<a href="http://www.example.com/" title="http://www.example.com/" rel="external">http://www.example.com</a>'),
array('http://example.com/',
'<a href="http://example.com/" rel="external">http://example.com/</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com/</a>'),
array('http://example.com/path',
'<a href="http://example.com/path" rel="external">http://example.com/path</a>'),
'<a href="http://example.com/path" title="http://example.com/path" rel="external">http://example.com/path</a>'),
array('http://example.com/path.html',
'<a href="http://example.com/path.html" rel="external">http://example.com/path.html</a>'),
'<a href="http://example.com/path.html" title="http://example.com/path.html" rel="external">http://example.com/path.html</a>'),
array('http://example.com/path.html#fragment',
'<a href="http://example.com/path.html#fragment" rel="external">http://example.com/path.html#fragment</a>'),
'<a href="http://example.com/path.html#fragment" title="http://example.com/path.html#fragment" rel="external">http://example.com/path.html#fragment</a>'),
array('http://example.com/path.php?foo=bar&bar=foo',
'<a href="http://example.com/path.php?foo=bar&amp;bar=foo" rel="external">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
'<a href="http://example.com/path.php?foo=bar&amp;bar=foo" title="http://example.com/path.php?foo=bar&amp;bar=foo" rel="external">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
array('http://example.com.',
'<a href="http://example.com/" rel="external">http://example.com</a>.'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'),
array('http://müllärör.de',
'<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="external">http://müllärör.de</a>'),
'<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" title="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="external">http://müllärör.de</a>'),
array('http://ﺱﺲﺷ.com',
'<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="external">http://ﺱﺲﺷ.com</a>'),
'<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" title="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="external">http://ﺱﺲﺷ.com</a>'),
array('http://сделаткартинки.com',
'<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="external">http://сделаткартинки.com</a>'),
'<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" title="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="external">http://сделаткартинки.com</a>'),
array('http://tūdaliņ.lv',
'<a href="http://t&#x16B;dali&#x146;.lv/" rel="external">http://tūdaliņ.lv</a>'),
'<a href="http://t&#x16B;dali&#x146;.lv/" title="http://t&#x16B;dali&#x146;.lv/" rel="external">http://tūdaliņ.lv</a>'),
array('http://brændendekærlighed.com',
'<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="external">http://brændendekærlighed.com</a>'),
'<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" title="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="external">http://brændendekærlighed.com</a>'),
array('http://あーるいん.com',
'<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="external">http://あーるいん.com</a>'),
'<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" title="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="external">http://あーるいん.com</a>'),
array('http://예비교사.com',
'<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="external">http://예비교사.com</a>'),
'<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" title="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="external">http://예비교사.com</a>'),
array('http://example.com.',
'<a href="http://example.com/" rel="external">http://example.com</a>.'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'),
array('http://example.com?',
'<a href="http://example.com/" rel="external">http://example.com</a>?'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>?'),
array('http://example.com!',
'<a href="http://example.com/" rel="external">http://example.com</a>!'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>!'),
array('http://example.com,',
'<a href="http://example.com/" rel="external">http://example.com</a>,'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>,'),
array('http://example.com;',
'<a href="http://example.com/" rel="external">http://example.com</a>;'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>;'),
array('http://example.com:',
'<a href="http://example.com/" rel="external">http://example.com</a>:'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>:'),
array('\'http://example.com\'',
'\'<a href="http://example.com/" rel="external">http://example.com</a>\''),
'\'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>\''),
array('"http://example.com"',
'&quot;<a href="http://example.com/" rel="external">http://example.com</a>&quot;'),
'&quot;<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>&quot;'),
array('http://example.com',
'<a href="http://example.com/" rel="external">http://example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
array('(http://example.com)',
'(<a href="http://example.com/" rel="external">http://example.com</a>)'),
'(<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>)'),
array('[http://example.com]',
'[<a href="http://example.com/" rel="external">http://example.com</a>]'),
'[<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>]'),
array('<http://example.com>',
'&lt;<a href="http://example.com/" rel="external">http://example.com</a>&gt;'),
'&lt;<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>&gt;'),
array('http://example.com/path/(foo)/bar',
'<a href="http://example.com/path/(foo)/bar" rel="external">http://example.com/path/(foo)/bar</a>'),
'<a href="http://example.com/path/(foo)/bar" title="http://example.com/path/(foo)/bar" rel="external">http://example.com/path/(foo)/bar</a>'),
array('http://example.com/path/[foo]/bar',
'<a href="http://example.com/path/[foo]/bar" rel="external">http://example.com/path/[foo]/bar</a>'),
'<a href="http://example.com/path/[foo]/bar" title="http://example.com/path/[foo]/bar" rel="external">http://example.com/path/[foo]/bar</a>'),
array('http://example.com/path/foo/(bar)',
'<a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>'),
'<a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>'),
//Not a valid url - urls cannot contain unencoded square brackets
array('http://example.com/path/foo/[bar]',
'<a href="http://example.com/path/foo/[bar]" rel="external">http://example.com/path/foo/[bar]</a>'),
'<a href="http://example.com/path/foo/[bar]" title="http://example.com/path/foo/[bar]" rel="external">http://example.com/path/foo/[bar]</a>'),
array('Hey, check out my cool site http://example.com okay?',
'Hey, check out my cool site <a href="http://example.com/" rel="external">http://example.com</a> okay?'),
'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a> okay?'),
array('What about parens (e.g. http://example.com/path/foo/(bar))?',
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)?'),
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)?'),
array('What about parens (e.g. http://example.com/path/foo/(bar)?',
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>?'),
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>?'),
array('What about parens (e.g. http://example.com/path/foo/(bar).)?',
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>.)?'),
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>.)?'),
//Not a valid url - urls cannot contain unencoded commas
array('What about parens (e.g. http://example.com/path/(foo,bar)?',
'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" rel="external">http://example.com/path/(foo,bar)</a>?'),
'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="external">http://example.com/path/(foo,bar)</a>?'),
array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?',
'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" rel="external">http://example.com/path/((((foo)/bar)</a>?'),
'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" title="http://example.com/path/((((foo)/bar)" rel="external">http://example.com/path/((((foo)/bar)</a>?'),
array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?',
'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" rel="external">http://example.com/path/(foo))))/bar</a>)?'),
'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" title="http://example.com/path/(foo))))/bar" rel="external">http://example.com/path/(foo))))/bar</a>)?'),
array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?',
'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" rel="external">http://example.com/path/foo/((((bar)</a>?'),
'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" title="http://example.com/path/foo/((((bar)" rel="external">http://example.com/path/foo/((((bar)</a>?'),
array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?',
'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)))?'),
'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)))?'),
array('example.com',
'<a href="http://example.com/" rel="external">example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
array('example.org',
'<a href="http://example.org/" rel="external">example.org</a>'),
'<a href="http://example.org/" title="http://example.org/" rel="external">example.org</a>'),
array('example.co.uk',
'<a href="http://example.co.uk/" rel="external">example.co.uk</a>'),
'<a href="http://example.co.uk/" title="http://example.co.uk/" rel="external">example.co.uk</a>'),
array('www.example.co.uk',
'<a href="http://www.example.co.uk/" rel="external">www.example.co.uk</a>'),
'<a href="http://www.example.co.uk/" title="http://www.example.co.uk/" rel="external">www.example.co.uk</a>'),
array('farm1.images.example.co.uk',
'<a href="http://farm1.images.example.co.uk/" rel="external">farm1.images.example.co.uk</a>'),
'<a href="http://farm1.images.example.co.uk/" title="http://farm1.images.example.co.uk/" rel="external">farm1.images.example.co.uk</a>'),
array('example.museum',
'<a href="http://example.museum/" rel="external">example.museum</a>'),
'<a href="http://example.museum/" title="http://example.museum/" rel="external">example.museum</a>'),
array('example.travel',
'<a href="http://example.travel/" rel="external">example.travel</a>'),
'<a href="http://example.travel/" title="http://example.travel/" rel="external">example.travel</a>'),
array('example.com.',
'<a href="http://example.com/" rel="external">example.com</a>.'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.'),
array('example.com?',
'<a href="http://example.com/" rel="external">example.com</a>?'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>?'),
array('example.com!',
'<a href="http://example.com/" rel="external">example.com</a>!'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>!'),
array('example.com,',
'<a href="http://example.com/" rel="external">example.com</a>,'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>,'),
array('example.com;',
'<a href="http://example.com/" rel="external">example.com</a>;'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>;'),
array('example.com:',
'<a href="http://example.com/" rel="external">example.com</a>:'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>:'),
array('\'example.com\'',
'\'<a href="http://example.com/" rel="external">example.com</a>\''),
'\'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>\''),
array('"example.com"',
'&quot;<a href="http://example.com/" rel="external">example.com</a>&quot;'),
'&quot;<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>&quot;'),
array('example.com',
'<a href="http://example.com/" rel="external">example.com</a>'),
'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
array('(example.com)',
'(<a href="http://example.com/" rel="external">example.com</a>)'),
'(<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>)'),
array('[example.com]',
'[<a href="http://example.com/" rel="external">example.com</a>]'),
'[<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>]'),
array('<example.com>',
'&lt;<a href="http://example.com/" rel="external">example.com</a>&gt;'),
'&lt;<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>&gt;'),
array('Hey, check out my cool site example.com okay?',
'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a> okay?'),
'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a> okay?'),
array('Hey, check out my cool site example.com.I made it.',
'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.I made it.'),
'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.I made it.'),
array('Hey, check out my cool site example.com.Funny thing...',
'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.Funny thing...'),
'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.Funny thing...'),
array('Hey, check out my cool site example.com.You will love it.',
'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.You will love it.'),
'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.You will love it.'),
array('What about parens (e.g. example.com/path/foo/(bar))?',
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>)?'),
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>)?'),
array('What about parens (e.g. example.com/path/foo/(bar)?',
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>?'),
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>?'),
array('What about parens (e.g. example.com/path/foo/(bar).)?',
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>.)?'),
'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>.)?'),
array('What about parens (e.g. example.com/path/(foo,bar)?',
'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" rel="external">example.com/path/(foo,bar)</a>?'),
'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="external">example.com/path/(foo,bar)</a>?'),
array('file.ext',
'file.ext'),
array('file.html',

59
tests/UserRightsTest.php Normal file
View File

@ -0,0 +1,59 @@
<?php
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
print "This script must be run from the command line\n";
exit();
}
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('STATUSNET', true);
require_once INSTALLDIR . '/lib/common.php';
class UserRightsTest extends PHPUnit_Framework_TestCase
{
protected $user = null;
function setUp()
{
$this->user = User::register(array('nickname' => 'userrightstestuser'));
}
function tearDown()
{
$profile = $this->user->getProfile();
$this->user->delete();
$profile->delete();
}
function testInvalidRole()
{
$this->assertFalse($this->user->hasRole('invalidrole'));
}
function standardRoles()
{
return array('admin', 'moderator');
}
/**
* @dataProvider standardRoles
*
*/
function testUngrantedRole($role)
{
$this->assertFalse($this->user->hasRole($role));
}
/**
* @dataProvider standardRoles
*
*/
function testGrantedRole($role)
{
$this->user->grantRole($role);
$this->assertFalse($this->user->hasRole($role));
}
}

View File

@ -251,7 +251,7 @@ margin-right:18px;
margin-bottom:11px;
margin-left:18px;
}
#site_nav_global_primary ul li {
#site_nav_global_primary li {
display:inline;
margin-left:11px;
}
@ -484,7 +484,7 @@ height:16px;
#form_notice .form_note {
position:absolute;
bottom:2px;
right:98px;
right:21.715%;
z-index:9;
}
#form_notice .form_note dt {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,698 +0,0 @@
/* CSS Document */
/* Design & CSS by Marie-Claude Doyon http://www.marieclaudedoyon.com */
/* Simplified for mobile by Ken Sheppardson http://identi.ca/kshep */
@import url(../../base/css/display.css);
html {}
body {
width: 100%;
padding: 0;
margin: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 24px;
min-height: 100%;
height: 100%;
color: #193441;
}
a {
color: #C15D42;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img, img a {
border: 0;
}
h1 {
font-size: 1.2em;
}
#wrap {
margin: 0;
}
#header {
width: 100%;
float: left;
background-color: #193441;
margin: 0 0 20px 0;
padding: 0;
}
#logo {
float: left;
margin: 10px 0px 0px 10px;
}
p#branding {
margin: 0;
padding: 6px 0 3px 0;
color: #fbf2d7;
font-size: 2em;
font-weight: bold;
line-height: 2.5em;
}
p#branding a {
color: #dab134;
}
#header h1.pagetitle {
display: none;
margin: 0;
padding: 0;
font-size: 1.2em;
line-height: 2em;
color: #d8e2d7;
}
#header h2.sitename {
display: none;
margin: 0;
padding: 0;
color: #FCFFF5;
}
/* ===== Begin Navigation Styling ===== */
/* ----- Navigation ------ */
#nav {
float: right;
margin: 0;
padding: 0;
list-style-type: none;
font-size: 1.2em;
}
#nav li {
display: block;
float: left;
}
#nav li a {
display: block;
padding: 9px 15px 12px 0px;
color: #91AA9D;
}
#nav li a:hover {
text-decoration: underline;
}
/* ----- Tabs ----- */
#nav_views {
clear: both;
float: left;
margin: 10px 0px 0px 5px;
padding: 0;
bottom: 0;
list-style-type: none;
font-size: 1.1em;
font-weight: bold;
}
#nav_views li {
display: block;
float: left;
line-height: 1.3em;
}
#nav_views li a {
display: block;
margin: 0;
padding: 4px 12px 3px 12px;
color: #FCFFF5;
background-color: #91AA9D;
border-right: 1px solid #6A8787;
}
#nav_views li a:hover {
text-decoration: none;
}
#nav_views li.current a, #nav_views li.current a:hover {
color: #3F606F;
background-color: #FCFFF5;
border-right: 1px solid #6A8787;
}
#nav_views li.current a:hover {
color: #193441;
}
#nav_views li a:hover {
color: #FCFFF5;
background-color: #3F606F;
border-right: 1px solid #6A8787;
}
/* ----- Nav Footer ----- */
#nav_sub {
clear: both;
margin: 18px 10px 0 10px;
padding: 0;
list-style-type: none;
font-size: 1.1em;
font-weight: bold;
line-height: 2em;
border-top: 1px solid #D8E2D7;
}
#nav_sub li {
display: block;
float: left;
}
#nav_sub li a {
padding: 6px 24px 6px 0;
}
#nav_sub li a:hover {
text-decoration: underline;
}
/* ===== End Navigation Styling ===== */
#content {
clear: left;
margin: 10px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 1em;
line-height: 1.1em;
}
#content h2 {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1.1em;
}
#content label {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1.1em;
}
.instructions {
clear: both;
float: left;
margin: 5px 5px 10px 5px;
}
.instructions p, .success, .error {
font-weight: normal;
margin: 0;
padding: 10px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 1.1em;
line-height: 1.2em;
border: 1px solid #91AA9D;
color: #FCFFF5;
}
.instructions a, .success a, .error a {
color: #d8e2d7;
text-decoration: underline;
}
.instructions a:hover, .success a:hover, .error a:hover {
color: #FCFFF5;
}
.success {
clear: both;
float: left;
margin: 5px 5px 10px 5px;
background-color: #48705b;
}
.error {
clear: both;
float: left;
margin: 5px 5px 10px 5px;
background-color: #ce3728;
}
/* ----- Stream -----*/
#notices {
clear: both;
margin: 0 auto;
padding: 0;
list-style-type: none;
border-top: 1px solid #D8E2D7;
}
#notices a:hover {
text-decoration: underline;
}
.notice_single {
clear: both;
display: block;
margin: 0;
padding: 5px 5px 5px 0;
min-height: 48px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 1em;
line-height: 1.4em;
border-bottom: 1px solid #D8E2D7;
}
.notice_single:hover {
background-color: #F3F8EA;
}
.notice_single p {
display: inline;
margin: 0;
padding: 0;
}
#notice_delete_form #confirmation_text {
display: block;
font-size: 1.1em;
font-weight: bold;
}
input#submit_yes, input#submit_no {
margin: 18px 10px 0px 0px;
padding: 4px;
font-weight: bold;
color: #FCFFF5;
background-color: #C15D42;
cursor: pointer;
border: 0;
width: 40px;
}
input#submit_yes:hover, input#submit_no:hover {
background-color: #904632;
}
.avatar.stream {
float: left;
margin: 0 10px 0 0;
}
p.time {
display: block;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 0.9em;
line-height: 2em;
}
p.time a {
color: #91AA9D;
}
/* ----- Profile -----*/
#profile {
clear: both;
float: left;
padding: 10px 0 0 0;
border-top: 1px solid #D8E2D7;
font-family: Georgia, "Times New Roman", Times, serif;
}
#profile h1 {
clear: both;
float: left;
margin: 0;
padding: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1.2em;
}
#profile h2 {
clear: both;
float: left;
margin: 0;
padding: 1em 0 0.2em 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1.1em;
text-transform: uppercase;
color: #91AA9D;
}
#profile p {
clear: both;
float: left;
margin: 0 10px 0 0;
font-size: 1em;
line-height: 1.4em;
}
#profile p.location {
margin: 0 10px 12px 0;
font-style: italic;
}
#profile p.notice_current {
font-size: 1.2em;
line-height: 1.3em;
}
#profile_avatar {
float: left;
margin-right: 4px;
}
#profile_avatar img {
margin-bottom: 5px;
}
.avatar.profile {
clear: left;
margin: 0 10px 5px 0;
}
.avatar.original {
float: left;
margin: 0 10px 18px 0;
}
a.nickname {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: 1.1em;
padding-right: 3px;
}
#profile_information {
float: left;
}
.statistics {
clear: both;
float: left;
}
.statistics h2 {
clear: both;
float: left;
margin: 12px 0 3px 0;
}
dl.statistics {
margin: 0;
}
.statistics dt {
clear: left;
float: left;
width: 200px;
}
.statistics dd {
float: left;
}
.statistics dt:after {
content: ":";
}
#subscriptions {
clear: both;
float: left;
margin: 18px 0 30px 0;
}
#subscriptions_avatars {
clear: both;
float: left;
margin: 6px 0 0 0;
padding: 0;
list-style-type: none;
}
#subscriptions_avatars li .avatar.mini {
float: left;
margin: 0 3px 3px 0;
padding: 0;
line-height: 0;
}
#subscriptions_viewall {
clear: left;
}
/* ----- End Profile -----*/
/* ----- Begin Subscriptions & Subscribers -----*/
ul.subscriptions, ul.subscribers {
float: none;
margin: 0;
padding: 0;
list-style-type: none;
overflow: auto;
}
ul.subscriptions li, ul.subscribers li {
display: block;
float: left;
padding: 0;
}
/* ----- End Subscriptions & Subscribers -----*/
#pagination {
margin: 18px auto;
}
#nav_pagination {
margin: 0 0 36px 0;
padding: 0;
float: right;
list-style-type: none;
font-size: 12px;
font-weight: bold;
}
#nav_pagination li {
display: block;
float: left;
background-color: #91AA9D;
}
#nav_pagination li.before {
margin-right: 1px;
}
#nav_pagination li a {
padding: 6px 15px;
line-height: 2em;
background-color: #91AA9D;
color: #FCFFF5;
}
#nav_pagination li a:hover {
background-color: #3F606F;
color: #FCFFF5;
text-decoration: none;
}
#footer {
clear: both;
margin: 10px;
border-top: 1px solid #D8E2D7;
}
#footer p {
font-size: 0.8em;
margin-top: 1em;
line-height: 1.2em;
}
#cc {
float: left;
margin: 3px 10px 0 0;
}
/* ===== Begin Forms Styling ===== */
/* ----- Forms General Style ----- */
form {
margin: 0 auto;
padding: 0;
}
form {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1em;
}
form label {
display: block;
font-size: 1em;
font-weight: bold;
line-height: 1.5em;
}
form input {
border: 1px solid #D8E2D7;
width: 264px;
}
input#submit, input.submit {
display: block;
margin: 18px 0;
padding: 4px;
font-weight: bold;
color: #FCFFF5;
background-color: #C15D42;
cursor: pointer;
border: 0;
width: auto;
}
input#submit:hover, input.submit:hover {
background-color: #904632;
}
input.checkbox {
width: auto;
border: 0;
}
textarea, input {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1em;
color: #193441;
padding: 3px;
}
textarea:focus, input:focus {
background-color: #f0f6eb;
}
textarea {
width: 270px;
border: 1px solid #D8E2D7;
}
.input_instructions {
margin-top: 3px;
display: block;
font-size: 1em;
line-height: 1.2em;
color: #91aa9d;
font-family: Verdana, Arial, Helvetica, sans-serif;
}
/* ----- Status Form ----- */
#status_form {
width: 100%;
margin: 0px 0px 10px 5px;
}
#status_form p {
margin: 0;
padding: 0;
}
#status_label {
display: none;
clear: both;
margin: 0;
padding: 0 0 3px 0;
font-size: 1.5em;
font-weight: bold;
line-height: 2em;
color: #91AA9D;
}
#status_textarea {
display: block;
float: left;
width: 70%;
height: 3em;
margin: 0 0 10px 0;
padding: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1.1em;
color: #193441;
border: 0;
}
#status_submit {
display: block;
float: left;
margin: 0 0 0 4px;
padding: 1em 10px 1em 10px;
line-height: 1em;
width: 10%;
background-color: #C15D42;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: 1em;
color: #FCFFF5;
cursor: pointer;
border: 0;
}
#status_submit:hover {
background-color: #904632;
}
#counter {
padding: 1em .5em 1em 5px;
color: #fff;
clear: both;
float: left;
font-weight: bold;
text-align: right;
}
/* ----- Subscribe Form ----- */
#subscribe .submit, #unsubscribe .submit, #remotesubscribe .button, #remotesubscribe {
clear: left;
margin: 0;
width: 96px;
height: 27px;
font-family: verdana, arial, helvetica, sans-serif;
font-weight: bold;
font-size: 12px;
text-transform: uppercase;
background-color: #c15d42;
color: #fcfff5;
border: 0;
}
#remotesubscribe {
width: 96px;
height: 22px;
padding: 5px 0 0 0;
text-align: center;
}
#subscribe .button:hover, #unsubscribe .button:hover {
background-color: #904632;
cursor: pointer;
}
a#remotesubscribe {
display: block;
}
/* ----- Login Form -----*/
input#license {
width: auto;
border: 0;
}
/* ----- Avatar Form -----*/
form {
clear: left;
}
/* ----- OpenID Form -----*/
input#openid_url {
background: url(login-bg.gif) no-repeat;
background-color: #fff;
background-position: 4px 50%;
color: #000;
padding-left: 24px;
}
/* People lists (search results, maybe subscribers) */
#profiles {
clear: both;
margin: 0 auto;
padding: 0;
list-style-type: none;
border-top: 1px solid #D8E2D7;
}
#profiles a:hover {
text-decoration: underline;
}
.profile_single {
clear: both;
display: block;
margin: 0;
padding: 5px 5px 5px 0;
min-height: 48px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 1.2em;
line-height: 1.4em;
border-bottom: 1px solid #D8E2D7;
}
.profile_single:hover {
background-color: #F3F8EA;
}
/* ----- IM Settings Form -----*/
#imsettings p {
margin: 0;
padding: 0;
line-height: 1.3em;
}
/* ===== End Forms Styling ===== */
/* ===== Tag Cloud Styling ===== */
p.tagcloud {
text-align: center;
}
p.tagcloud a {
line-height:1em;
vertical-align:middle;
}
p.tagcloud a.largest {
font-size: 4em;
}
p.tagcloud a.verylarge {
font-size: 3em;
}
p.tagcloud a.large {
font-size: 2em;
}
p.tagcloud a.medium {
font-size: 1.5em;
}
p.tagcloud a.small {
font-size: 1em;
}
p.tagcloud a.verysmall {
font-size: 80%;
}
p.tagcloud a.smallest {
font-size: 60%;
}
a.replybutton {
border: 1px solid #D8E2D7;
padding: 0px 10px 0px 10px;
line-height: 0.8em;
}

View File

@ -1,686 +0,0 @@
/* CSS Document */
/* Design & CSS by Marie-Claude Doyon http://www.marieclaudedoyon.com */
html {
background: url(bg-body.gif) repeat-y top center #d8e2d7;
}
body {
position: absolute;
width: 100%;
margin: 0;
padding: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10px;
line-height: 12px;
min-height: 100%;
height: 100%;
color: #193441;
}
a {
color: #C15D42;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img, img a {
border: 0;
}
h1 {
font-size: 14px;
}
#wrap {
margin: 0 auto;
padding: 0 20px;
width: 760px;
background: url(bg-header.gif) repeat-x #FCFFF5;
}
#header {
position: relative;
margin: 0 auto;
width: 540px;
height: 216px;
}
#logo {
margin-top: 9px;
}
p#branding {
margin: 0;
padding: 6px 0 3px 0;
color: #fbf2d7;
font-size: 21px;
font-weight: bold;
line-height: 27px;
}
p#branding a {
color: #dab134;
}
#header h1.pagetitle {
margin: 0;
padding: 0;
font-size: 15px;
line-height: 24px;
color: #d8e2d7;
}
#header h2.sitename {
display: none;
margin: 0;
padding: 0;
color: #FCFFF5;
}
/* ===== Begin Navigation Styling ===== */
/* ----- Navigation ------ */
#nav {
float: right;
margin: 0;
padding: 0;
list-style-type: none;
font-size: 12px;
}
#nav li {
display: block;
float: left;
}
#nav li a {
display: block;
padding: 9px 9px 12px 9px;
color: #91AA9D;
}
#nav li a:hover {
text-decoration: underline;
}
/* ----- Tabs ----- */
#nav_views {
margin: 0 auto;
padding: 0;
position: absolute;
bottom: 0;
list-style-type: none;
font-size: 14px;
font-weight: bold;
width: 540px;
/*height: 30px;*/
}
#nav_views li {
display: block;
float: left;
line-height: 21px;
}
#nav_views li a {
display: block;
margin: 0;
padding: 4px 12px 3px 12px;
color: #FCFFF5;
background-color: #91AA9D;
border-right: 1px solid #6A8787;
}
#nav_views li a:hover {
text-decoration: none;
}
#nav_views li.current a, #nav_views li.current a:hover {
color: #3F606F;
background-color: #FCFFF5;
border-right: 1px solid #6A8787;
}
#nav_views li.current a:hover {
color: #193441;
}
#nav_views li a:hover {
color: #FCFFF5;
background-color: #3F606F;
border-right: 1px solid #6A8787;
}
/* ----- Nav Footer ----- */
#nav_sub {
clear: both;
margin: 18px auto 0 auto;
padding: 0;
list-style-type: none;
font-size: 11px;
font-weight: bold;
line-height: 21px;
border-top: 1px solid #D8E2D7;
width: 540px;
}
#nav_sub li {
display: block;
float: left;
}
#nav_sub li a {
padding: 6px 24px 6px 0;
}
#nav_sub li a:hover {
text-decoration: underline;
}
/* ===== End Navigation Styling ===== */
#content {
clear: left;
margin: 40px 0 45px 0;
padding: 0 110px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 14px;
line-height: 18px;
}
#content h2 {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 15px;
}
#content label {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
}
.instructions p, .success, .error {
font-weight: normal;
margin: 36px 0 0 0;
padding: 10px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 13px;
line-height: 15px;
border: 1px solid #91AA9D;
color: #FCFFF5;
}
.instructions a, .success a, .error a {
color: #d8e2d7;
text-decoration: underline;
}
.instructions a:hover, .success a:hover, .error a:hover {
color: #FCFFF5;
}
.success {
background-color: #48705b;
}
.error {
background-color: #ce3728;
}
/* ----- Stream -----*/
#notices {
clear: both;
margin: 0 auto;
padding: 0;
list-style-type: none;
width: 540px;
border-top: 1px solid #D8E2D7;
}
#notices a:hover {
text-decoration: underline;
}
.notice_single {
clear: both;
display: block;
margin: 0;
padding: 5px 5px 5px 0;
min-height: 48px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 13px;
line-height: 16px;
border-bottom: 1px solid #D8E2D7;
}
.notice_single:hover {
background-color: #F3F8EA;
}
.notice_single p {
display: inline;
margin: 0;
padding: 0;
}
#notice_delete_form #confirmation_text {
display: block;
font-size: 14px;
font-weight: bold;
}
input#submit_yes, input#submit_no {
margin: 18px 10px 0px 0px;
padding: 4px;
font-weight: bold;
color: #FCFFF5;
background-color: #C15D42;
cursor: pointer;
border: 0;
width: 40px;
}
input#submit_yes:hover, input#submit_no:hover {
background-color: #904632;
}
.avatar.stream {
float: left;
margin: 0 10px 0 0;
}
p.time {
display: block;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10px;
line-height: 15px;
}
p.time a {
color: #91AA9D;
}
/* ----- Profile -----*/
#profile {
clear: left;
margin: 0 -110px;
padding: 10px 0 0 0;
min-height: 170px;
border-top: 1px solid #D8E2D7;
font-family: Georgia, "Times New Roman", Times, serif;
}
#profile h1 {
margin: 0;
padding: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 14px;
}
#profile h2 {
margin: 0;
padding: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
text-transform: uppercase;
color: #91AA9D;
}
#profile p {
margin: 0 10px 0 0;
font-size: 12px;
line-height: 14px;
}
#profile p.location {
margin: 0 10px 12px 0;
font-style: italic;
}
#profile p.notice_current {
font-size: 18px;
line-height: 21px;
}
#profile_avatar {
float: left;
margin-right: 4px;
}
#profile_avatar img {
margin-bottom: 5px;
}
.avatar.profile {
clear: left;
margin: 0 10px 5px 0;
}
.avatar.original {
float: left;
margin: 0 10px 18px 0;
}
a.nickname {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: 12px;
padding-right: 3px;
}
#profile_information {
float: left;
position: relative;
width: 270px;
height: 200px;
}
.statistics {
margin-top: 18px;
}
.statistics h2 {
margin: 12px 0 3px 0;
}
dl.statistics {
margin: 0;
font-size: 12px;
line-height: 14px;
}
.statistics dt {
float: left;
width: 96px;
}
.statistics dd {
margin-left: 100px;
}
.statistics dt:after {
content: ":";
}
#subscriptions {
float: left;
margin: 18px 0 30px 0;
}
#subscriptions_avatars {
float: left;
margin: 6px 0 0 0;
padding: 0;
list-style-type: none;
width: 270px;
}
#subscriptions_avatars li .avatar.mini {
float: left;
margin: 0 3px 3px 0;
padding: 0;
line-height: 0;
/* border: 1px solid #f00; */
}
#subscriptions_viewall {
clear: left;
}
/* ----- End Profile -----*/
/* ----- Begin Subscriptions & Subscribers -----*/
ul.subscriptions, ul.subscribers {
float: none;
margin: 0;
padding: 0;
list-style-type: none;
overflow: auto;
}
ul.subscriptions li, ul.subscribers li {
display: block;
float: left;
padding: 0;
}
/* ----- End Subscriptions & Subscribers -----*/
#pagination {
margin: 18px auto;
width: 540px;
}
#nav_pagination {
margin: 0 0 36px 0;
padding: 0;
float: right;
list-style-type: none;
font-size: 12px;
font-weight: bold;
}
#nav_pagination li {
display: block;
float: left;
background-color: #91AA9D;
}
#nav_pagination li.before {
margin-right: 1px;
}
#nav_pagination li a {
padding: 6px 15px;
line-height: 21px;
background-color: #91AA9D;
color: #FCFFF5;
}
#nav_pagination li a:hover {
background-color: #3F606F;
color: #FCFFF5;
text-decoration: none;
}
#footer {
clear: both;
margin: 0 auto;
padding: 0 0 36px 0;
width: 540px;
border-top: 1px solid #D8E2D7;
}
#footer p {
margin-top: 9px;
line-height: 12px;
}
#cc {
float: left;
margin: 3px 10px 0 0;
}
/* ===== Begin Forms Styling ===== */
/* ----- Forms General Style ----- */
form {
margin: 0 auto;
padding: 0;
}
form {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
}
form label {
display: block;
font-size: 12px;
font-weight: bold;
line-height: 18px;
}
form input {
border: 1px solid #D8E2D7;
width: 264px;
}
input#submit, input.submit {
display: block;
margin: 18px 0;
padding: 4px;
font-weight: bold;
color: #FCFFF5;
background-color: #C15D42;
cursor: pointer;
border: 0;
width: auto;
}
input#submit:hover, input.submit:hover {
background-color: #904632;
}
input.checkbox {
/*width: 14px;
height: 14px;*/
width: auto;
border: 0;
}
textarea, input {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
color: #193441;
padding: 3px;
}
textarea:focus, input:focus {
background-color: #f0f6eb;
}
textarea {
width: 270px;
border: 1px solid #D8E2D7;
}
.input_instructions {
margin-top: 3px;
display: block;
font-size: 11px;
line-height: 15px;
color: #91aa9d;
font-family: Verdana, Arial, Helvetica, sans-serif;
}
/* ----- Status Form ----- */
#status_form {
height: 96px;
/*background-color: #F00;*/
}
#status_form p {
margin: 36px 0 0 0;
padding: 0;
}
#status_label {
display: block;
clear: both;
margin: 0;
padding: 0 0 3px 0;
font-size: 18px;
font-weight: bold;
line-height: 24px;
color: #91AA9D;
}
#status_textarea {
display: block;
float: left;
width: 463px;
height: 35px;
padding: 5px;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
color: #193441;
border: 0;
}
#status_submit {
display: block;
float: left;
margin: 1px 0 0 4px;
width: 63px;
height: 45px;
background-color: #C15D42;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: 14px;
color: #FCFFF5;
cursor: pointer;
border: 0;
}
#status_submit:hover {
background-color: #904632;
}
#counter {
position: absolute;
top: 140px;
left: -64px;
width: 50px;
font-weight: bold;
text-align: right;
}
/* ----- Subscribe Form ----- */
#subscribe .submit, #unsubscribe .submit, #remotesubscribe .button, #remotesubscribe {
clear: left;
margin: 0;
width: 96px;
height: 27px;
font-family: verdana, arial, helvetica, sans-serif;
font-weight: bold;
font-size: 10px;
text-transform: uppercase;
background-color: #c15d42;
color: #fcfff5;
border: 0;
}
#remotesubscribe {
width: 96px;
height: 22px;
padding: 5px 0 0 0;
text-align: center;
}
#subscribe .button:hover, #unsubscribe .button:hover {
background-color: #904632;
cursor: pointer;
}
a#remotesubscribe {
display: block;
}
/* ----- Login Form -----*/
input#license {
width: auto;
border: 0;
}
/* ----- Avatar Form -----*/
form {
clear: left;
}
/* ----- OpenID Form -----*/
input#openid_url {
background: url(login-bg.gif) no-repeat;
background-color: #fff;
background-position: 4px 50%;
color: #000;
padding-left: 24px;
}
/* People lists (search results, maybe subscribers) */
#profiles {
clear: both;
margin: 0 auto;
padding: 0;
list-style-type: none;
width: 540px;
border-top: 1px solid #D8E2D7;
/*border: 1px solid #F00;*/
}
#profiles a:hover {
text-decoration: underline;
}
.profile_single {
clear: both;
display: block;
margin: 0;
padding: 5px 5px 5px 0;
min-height: 48px;
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 13px;
line-height: 16px;
border-bottom: 1px solid #D8E2D7;
}
.profile_single:hover {
background-color: #F3F8EA;
}
/* ----- IM Settings Form -----*/
#imsettings p {
margin: 0;
padding: 0;
line-height: 15px;
}
/* ===== End Forms Styling ===== */
/* ===== Tag Cloud Styling ===== */
p.tagcloud {
text-align: center;
}
p.tagcloud a {
line-height:100%;
vertical-align:middle;
}
p.tagcloud a.largest {
font-size: 400%;
}
p.tagcloud a.verylarge {
font-size: 300%;
}
p.tagcloud a.large {
font-size: 200%;
}
p.tagcloud a.medium {
font-size: 150%;
}
p.tagcloud a.small {
font-size: 100%;
}
p.tagcloud a.verysmall {
font-size: 80%;
}
p.tagcloud a.smallest {
font-size: 60%;
}

View File

@ -1,63 +0,0 @@
@charset "UTF-8";
/* CSS Document */
body {
text-align: center;
}
input {
height: 24px;
}
#wrap {
margin: 0 auto;
padding: 0 20px;
width: 800px;
text-align: left;
background: url(bg-header.gif) repeat-x #FCFFF5;
}
#header {
position: relative;
margin-left: 108px;
}
#nav_views {
margin: 0;
}
#nav_views li {
line-height: 19px;
}
.statistics dd {
margin-top: -15px;
clear: both;
}
#notices {
margin: 0;
}
.notice_single {
height: 48px;
}
#profile p.notice_current {
height: 96px;
}
#subscriptions_avatars li {
float: left;
margin: 0;
padding: 0;
}
img.avatar.original, img.avatar.profile {
clear: none;
float: left;
}
#status_textarea {
height: 46px;
}
#nav_pagination li a {
padding: 6px 15px;
line-height: 27px;
}
#nav_sub {
position: relative;
margin-left: 108px;
}
#footer {
margin-left: 108px;
}

View File

@ -1,20 +0,0 @@
@charset "UTF-8";
/* CSS Document */
#statistics dd {
clear: both;
}
#subscriptions_avatars li {
float: left;
}
img.avatar.original, img.avatar.profile {
clear: none;
float: left;
}
#nav_pagination li a {
padding: 6px 15px;
line-height: 27px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 818 B