diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/action.php | 24 | ||||
-rw-r--r-- | lib/clienterroraction.php | 43 | ||||
-rw-r--r-- | lib/common.php | 218 | ||||
-rw-r--r-- | lib/default.php | 233 | ||||
-rw-r--r-- | lib/deleteaction.php | 74 | ||||
-rw-r--r-- | lib/error.php | 6 | ||||
-rw-r--r-- | lib/facebookaction.php | 10 | ||||
-rw-r--r-- | lib/htmloutputter.php | 24 | ||||
-rw-r--r-- | lib/noticelist.php | 5 | ||||
-rw-r--r-- | lib/oauthstore.php | 5 | ||||
-rw-r--r-- | lib/right.php | 50 | ||||
-rw-r--r-- | lib/router.php | 4 | ||||
-rw-r--r-- | lib/schema.php | 680 | ||||
-rw-r--r-- | lib/servererroraction.php | 19 | ||||
-rw-r--r-- | lib/twitterapi.php | 56 | ||||
-rw-r--r-- | lib/util.php | 23 |
16 files changed, 1092 insertions, 382 deletions
diff --git a/lib/action.php b/lib/action.php index 02793f069..1b2f73752 100644 --- a/lib/action.php +++ b/lib/action.php @@ -120,14 +120,16 @@ class Action extends HTMLOutputter // lawsuit { // XXX: attributes (profile?) $this->elementStart('head'); - $this->showTitle(); - $this->showShortcutIcon(); - $this->showStylesheets(); - $this->showScripts(); - $this->showOpenSearch(); - $this->showFeeds(); - $this->showDescription(); - $this->extraHead(); + if (Event::handle('StartShowHeadElements', array($this))) { + $this->showTitle(); + $this->showShortcutIcon(); + $this->showStylesheets(); + $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)); } - $this->showAside(); + if (Event::handle('StartShowAside', array($this))) { + $this->showAside(); + Event::handle('EndShowAside', array($this)); + } $this->elementEnd('div'); } diff --git a/lib/clienterroraction.php b/lib/clienterroraction.php index 7d007a756..1b98a1064 100644 --- a/lib/clienterroraction.php +++ b/lib/clienterroraction.php @@ -46,28 +46,28 @@ require_once INSTALLDIR.'/lib/error.php'; */ class ClientErrorAction extends ErrorAction { + 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'); + function __construct($message='Error', $code=400) { parent::__construct($message, $code); - - $this->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'); $this->default = 400; } @@ -91,9 +91,4 @@ class ClientErrorAction extends ErrorAction $this->showPage(); } - - function title() - { - return $this->status[$this->code]; - } } diff --git a/lib/common.php b/lib/common.php index 194eb568f..ce33c871b 100644 --- a/lib/common.php +++ b/lib/common.php @@ -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'); + +// Set config values initially to default values + +$config = $default; -$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? - ); +// 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); diff --git a/lib/default.php b/lib/default.php new file mode 100644 index 000000000..f9670cb7f --- /dev/null +++ b/lib/default.php @@ -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? + ); diff --git a/lib/deleteaction.php b/lib/deleteaction.php deleted file mode 100644 index f702820c6..000000000 --- a/lib/deleteaction.php +++ /dev/null @@ -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; - } - } - -} diff --git a/lib/error.php b/lib/error.php index 0c521db08..6a9b76be1 100644 --- a/lib/error.php +++ b/lib/error.php @@ -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) diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 411f79594..3f3a8d3b0 100644 --- a/lib/facebookaction.php +++ b/lib/facebookaction.php @@ -468,11 +468,11 @@ class FacebookAction extends Action $replyto = $this->trimmed('inreplyto'); - $notice = Notice::saveNew($user->id, $content, - 'web', 1, ($replyto == 'false') ? null : $replyto); - - if (is_string($notice)) { - $this->showPage($notice); + try { + $notice = Notice::saveNew($user->id, $content, + 'web', 1, ($replyto == 'false') ? null : $replyto); + } catch (Exception $e) { + $this->showPage($e->getMessage()); return; } diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index aa01f6b1d..ce83295fb 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -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'); } } diff --git a/lib/noticelist.php b/lib/noticelist.php index c2ff7c26b..6c296f82a 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -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, diff --git a/lib/oauthstore.php b/lib/oauthstore.php index e69a00f55..d617a7df7 100644 --- a/lib/oauthstore.php +++ b/lib/oauthstore.php @@ -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); } diff --git a/lib/right.php b/lib/right.php new file mode 100644 index 000000000..4e0096d46 --- /dev/null +++ b/lib/right.php @@ -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'; +} + diff --git a/lib/router.php b/lib/router.php index c18f273ed..91f886bce 100644 --- a/lib/router.php +++ b/lib/router.php @@ -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]+')); diff --git a/lib/schema.php b/lib/schema.php new file mode 100644 index 000000000..1e0c1f3e9 --- /dev/null +++ b/lib/schema.php @@ -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)); + } +} diff --git a/lib/servererroraction.php b/lib/servererroraction.php index c6400605e..0993a63bc 100644 --- a/lib/servererroraction.php +++ b/lib/servererroraction.php @@ -55,17 +55,17 @@ require_once INSTALLDIR.'/lib/error.php'; class ServerErrorAction extends ErrorAction { + 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->status = array(500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported'); - $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]; - } } diff --git a/lib/twitterapi.php b/lib/twitterapi.php index d199e4dee..4a5de6ab3 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -502,7 +502,7 @@ class TwitterapiAction extends Action $enclosure = $entry['enclosures'][0]; $this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null); } - + if(array_key_exists('tags', $entry)){ foreach($entry['tags'] as $tag){ $this->element('category', null,$tag); @@ -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(); diff --git a/lib/util.php b/lib/util.php index 56753debe..d249b154f 100644 --- a/lib/util.php +++ b/lib/util.php @@ -522,20 +522,21 @@ 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); + $canon = File_redirection::_canonUrl($url); - $longurl_data = File_redirection::where($url); - if (is_array($longurl_data)) { - $longurl = $longurl_data['url']; - } elseif (is_string($longurl_data)) { - $longurl = $longurl_data; - } else { - throw new ServerException("Can't linkify url '$url'"); + $longurl_data = File_redirection::where($canon); + if (is_array($longurl_data)) { + $longurl = $longurl_data['url']; + } elseif (is_string($longurl_data)) { + $longurl = $longurl_data; + } else { + throw new ServerException("Can't linkify url '$url'"); + } } - $attrs = array('href' => $canon, 'title' => $longurl, 'rel' => 'external'); $is_attachment = false; |