From 51ac34e80c5a99008b1a945b2c00b6dbfdde1529 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 26 Jul 2009 13:06:38 -0600 Subject: [PATCH 01/73] first version of deleting users --- classes/Profile.php | 75 +++++++++++++++++++++++++++++++++++++++++++++ classes/User.php | 43 ++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/classes/Profile.php b/classes/Profile.php index f926b2cef2..0ee6fa657f 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -461,4 +461,79 @@ class Profile extends Memcached_DataObject $c->delete(common_cache_key('profile:notice_count:'.$this->id)); } } + + 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; + $msg->delete(); + } + + function _deleteBlocks() + { + $block = new Profile_block(); + $block->blocked = $this->id; + $block->delete(); + + $block = new Group_block(); + $block->blocked = $this->id; + $block->delete(); + } } diff --git a/classes/User.php b/classes/User.php index bea47a3b05..991e9c18fb 100644 --- a/classes/User.php +++ b/classes/User.php @@ -685,4 +685,47 @@ class User extends Memcached_DataObject { return Design::staticGet('id', $this->design_id); } + + 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(); + + 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? + } } From 131292472c4bca7e99ee821ae62853f36f4c7bef Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sat, 19 Sep 2009 18:34:07 -0700 Subject: [PATCH 02/73] Make statuses/home_timeline return the same thing as statuses/friends_timeline to support apps trying to use the new retweet API method. --- actions/twitapistatuses.php | 5 +++++ lib/router.php | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index edee239a03..5e2867ea81 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -136,6 +136,11 @@ class TwitapistatusesAction extends TwitterapiAction } + function home_timeline($args, $apidata) + { + call_user_func(array($this, 'friends_timeline'), $args, $apidata); + } + function user_timeline($args, $apidata) { parent::handle($args); diff --git a/lib/router.php b/lib/router.php index 00e728f557..5309fe7530 100644 --- a/lib/router.php +++ b/lib/router.php @@ -268,12 +268,12 @@ class Router $m->connect('api/statuses/:method', array('action' => 'api', 'apiaction' => 'statuses'), - array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|mentions|show|friends|followers|featured)(\.(atom|rss|xml|json))?')); + array('method' => '(public_timeline|home_timeline|friends_timeline|user_timeline|update|replies|mentions|show|friends|followers|featured)(\.(atom|rss|xml|json))?')); $m->connect('api/statuses/:method/:argument', array('action' => 'api', 'apiaction' => 'statuses'), - array('method' => '(|user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)')); + array('method' => '(user_timeline|home_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)')); // users @@ -432,7 +432,7 @@ class Router $m->connect('api/statuses/:method/:argument', array('action' => 'api', 'apiaction' => 'statuses'), - array('method' => '(|user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)')); + array('method' => '(user_timeline|home_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)')); $m->connect('api/statusnet/groups/:method/:argument', array('action' => 'api', From 4f833531dd5aa05e56ab00dd95eda4ce8419564d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 20 Jul 2009 19:04:48 -0400 Subject: [PATCH 03/73] start a module for schema management --- lib/schema.php | 124 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 lib/schema.php diff --git a/lib/schema.php b/lib/schema.php new file mode 100644 index 0000000000..db2f49a789 --- /dev/null +++ b/lib/schema.php @@ -0,0 +1,124 @@ +. + * + * @category Database + * @package Laconica + * @author Evan Prodromou + * @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); +} + +/** + * 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 Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class Schema +{ + protected $db = null; + + static function get() + { + + } + + public function getTableDef($name) + { + } + + public function getColumnDef($table, $column) + { + } + + public function getIndexDef($table, $index) + { + } + + public function createTable($name, $columns, $indices=null) + { + } + + public function dropTable($name) + { + } + + public function createIndex($name, $table, $columns) + { + } + + public function dropIndex($name, $table) + { + } + + public function addColumn($table, $columndef) + { + } + + public function modifyColumn($table, $column, $columndef) + { + } + + public function dropColumn($table, $column) + { + } + + public function ensureTable($name, $columns, $indices) + { + $def = $this->tableDef($name); + if (empty($def)) { + return $this->createTable($name, $columns, $indices); + } + } +} + +class TableDef +{ + public $name; + public $columns; +} + +class ColumnDef +{ + public $name; + public $type; + public $size; +} + +class IndexDef +{ + public $name; + public $table; + public $columns; +} From f31653ca5bc06db4d1a2a2dc8a1943f2d99f735a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 24 Aug 2009 11:22:40 -0400 Subject: [PATCH 04/73] make table def method of schema code work --- lib/schema.php | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/lib/schema.php b/lib/schema.php index db2f49a789..624765eb2e 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -47,15 +47,65 @@ if (!defined('LACONICA')) { class Schema { - protected $db = null; + static $_single = null; + protected $conn = null; + + protected function __construct() + { + // XXX: there should be an easier way to do this. + $user = new User(); + $this->conn = $user->getDatabaseConnection(); + $user->free(); + unset($user); + } static function get() { - + if (empty(self::$_single)) { + self::$_single = new Schema(); + } + return self::$_single; } 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; } public function getColumnDef($table, $column) @@ -114,6 +164,10 @@ class ColumnDef public $name; public $type; public $size; + public $nullable; + public $key; + public $default; + public $extra; } class IndexDef From bd8a2dbfd68289a4f025964647320f8ef5e857aa Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 24 Aug 2009 11:23:02 -0400 Subject: [PATCH 05/73] test script for schema code --- scripts/showtable.php | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 scripts/showtable.php diff --git a/scripts/showtable.php b/scripts/showtable.php new file mode 100644 index 0000000000..30f0bb5a90 --- /dev/null +++ b/scripts/showtable.php @@ -0,0 +1,41 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$helptext = << +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); From e206324f245145a0e8c9ec0535cba1d62344ebf7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 23 Sep 2009 09:20:04 -0400 Subject: [PATCH 06/73] statusize schema-related modules --- lib/schema.php | 18 +++++++++--------- scripts/showtable.php | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/schema.php b/lib/schema.php index 624765eb2e..d3b30aeeb5 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -1,6 +1,6 @@ . * * @category Database - * @package Laconica - * @author Evan Prodromou - * @copyright 2009 Control Yourself, Inc. + * @package StatusNet + * @author Evan Prodromou + * @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://laconi.ca/ + * @link http://status.net/ */ -if (!defined('LACONICA')) { +if (!defined('STATUSNET')) { exit(1); } @@ -39,10 +39,10 @@ if (!defined('LACONICA')) { * utilities. * * @category Database - * @package Laconica - * @author Evan Prodromou + * @package StatusNet + * @author Evan Prodromou * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ + * @link http://status.net/ */ class Schema diff --git a/scripts/showtable.php b/scripts/showtable.php index 30f0bb5a90..eb18a98e20 100644 --- a/scripts/showtable.php +++ b/scripts/showtable.php @@ -1,8 +1,8 @@ #!/usr/bin/env php Date: Wed, 23 Sep 2009 22:24:35 -0400 Subject: [PATCH 07/73] use schema tool to create a table --- lib/schema.php | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/lib/schema.php b/lib/schema.php index d3b30aeeb5..f490756905 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -110,18 +110,87 @@ class Schema public function getColumnDef($table, $column) { + $td = $this->getTableDef($table); + + foreach ($td->columns as $cd) { + if ($cd->name == $column) { + return $cd; + } + } + + return null; } public function getIndexDef($table, $index) { + return null; } public function createTable($name, $columns, $indices=null) { + $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 .= "); "; + + common_debug($sql); + + $res =& $this->conn->query($sql); + + if (PEAR::isError($res)) { + throw new Exception($res->getMessage()); + } + + return true; } public function dropTable($name) { + $res =& $this->conn->query("DROP TABLE $name"); + + if (PEAR::isError($res)) { + throw new Exception($res->getMessage()); + } + + return true; } public function createIndex($name, $table, $columns) @@ -151,6 +220,25 @@ class Schema return $this->createTable($name, $columns, $indices); } } + + 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; + } } class TableDef @@ -168,6 +256,17 @@ class ColumnDef public $key; public $default; public $extra; + + function __construct($name, $type, $size=null, $nullable=null, + $key=null, $default=null, $extra=null) { + $this->name = $name; + $this->type = $type; + $this->size = $size; + $this->nullable = $nullable; + $this->key = $key; + $this->default = $default; + $this->extra = $extra; + } } class IndexDef From ecb75561af074160650ccf2a5fd79241701c347e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 24 Sep 2009 22:25:30 -0400 Subject: [PATCH 08/73] Move configuration defaults to new module and variable Moved the default values of $config to $default. The code for setting up $default is moved to lib/default.php. --- lib/common.php | 212 ++----------------------------------------- lib/default.php | 232 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 204 deletions(-) create mode 100644 lib/default.php diff --git a/lib/common.php b/lib/common.php index 194eb568f7..58e208a4e9 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'); -$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 diff --git a/lib/default.php b/lib/default.php new file mode 100644 index 0000000000..7af94d2ad6 --- /dev/null +++ b/lib/default.php @@ -0,0 +1,232 @@ +. + * + * @category Config + * @package StatusNet + * @author Evan Prodromou + * @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' ), + '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? + ); From bc2a0f550be71aea89b2c4f548aa187627bbbf38 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Fri, 25 Sep 2009 21:25:20 +0100 Subject: [PATCH 09/73] Updated Piwik plugin documentation to new addPlugin() installaation method --- plugins/PiwikAnalyticsPlugin.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/plugins/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalyticsPlugin.php index 8191f51811..54faa0bdbe 100644 --- a/plugins/PiwikAnalyticsPlugin.php +++ b/plugins/PiwikAnalyticsPlugin.php @@ -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 - * @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 From 2b6dfbdf2b9df0992018f8df1f54b4cf16185599 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sat, 26 Sep 2009 20:25:47 +0000 Subject: [PATCH 10/73] A different go at the realtime button location. Button is in a prominent location. --- plugins/Realtime/realtimeupdate.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 57fe0a8436..a31565177f 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -113,19 +113,19 @@ RealtimeUpdate = { addPopup: function(url, timeline, iconurl) { - $('#site_nav_local_views .current a').append(''); + $('#content').prepend(''); $('#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 18px 0', + 'background':'transparent url('+ iconurl + ') no-repeat 0% 30%', + 'padding':'0 0 0 20px', 'display':'block', 'float':'right', 'border':'none', - 'cursor':'pointer' + 'cursor':'pointer', + 'color':$("a").css("color"), + 'font-weight':'bold', + 'font-size':'1em' }); $('#realtime_timeline').click(function() { From 7d843b11228bb55750177ca7809d5f067d52dc20 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 11:31:34 +0000 Subject: [PATCH 11/73] jQuery.prepend takes a single param --- plugins/Realtime/realtimeupdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index a31565177f..765710bfe2 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -27,7 +27,7 @@ RealtimeUpdate = { } 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(); From a51339a2195caed5a3833346f508b38953e4618b Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 11:49:18 +0000 Subject: [PATCH 12/73] Don't really need the header container. Adjusted some CSS instead --- plugins/Realtime/RealtimePlugin.php | 3 --- plugins/Realtime/realtimeupdate.js | 10 +++++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php index e30c411567..0f0d0f9f42 100644 --- a/plugins/Realtime/RealtimePlugin.php +++ b/plugins/Realtime/RealtimePlugin.php @@ -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,7 +228,6 @@ class RealtimePlugin extends Plugin if (common_logged_in()) { $action->showNoticeForm(); } - $action->elementEnd('div'); $action->showContentBlock(); $action->elementEnd('body'); diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 765710bfe2..a5f6052eab 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -114,7 +114,7 @@ RealtimeUpdate = { addPopup: function(url, timeline, iconurl) { $('#content').prepend(''); - + $('#realtime_timeline').css({ 'margin':'0 0 18px 0', 'background':'transparent url('+ iconurl + ') no-repeat 0% 30%', @@ -127,12 +127,12 @@ RealtimeUpdate = { 'font-weight':'bold', 'font-size':'1em' }); - + $('#realtime_timeline').click(function() { window.open(url, timeline, 'toolbar=no,resizable=yes,scrollbars=yes,status=yes'); - + return false; }); }, @@ -142,6 +142,10 @@ RealtimeUpdate = { window.resizeTo(575, 640); $('address').hide(); $('#content').css({'width':'92%'}); + + $('#form_notice').css({ + 'margin':'18px 0 29px 1.795%' + }); } } From 74d537c834cf897e989d9909393c879129d99ae7 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 11:54:45 +0000 Subject: [PATCH 13/73] Using a relative value for the form_notice note location instead --- theme/base/css/display.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 1f37a7637b..7706fba484 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -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 { From 73c92045373d097d115d4016da092a6e0711ab04 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 27 Sep 2009 13:58:48 +0200 Subject: [PATCH 14/73] fix for a misnamed variable in subscription function in the "create simulation data" script --- scripts/createsim.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/createsim.php b/scripts/createsim.php index 71ed3bf722..1266a9700b 100644 --- a/scripts/createsim.php +++ b/scripts/createsim.php @@ -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'."); } From 4d92d7d52ff20b22232c32c40fc88a8d03085ec9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:15:37 +0000 Subject: [PATCH 15/73] Removed form_notice label and h1 from view --- plugins/Realtime/realtimeupdate.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index a5f6052eab..bcbf1ba287 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -144,8 +144,12 @@ RealtimeUpdate = { $('#content').css({'width':'92%'}); $('#form_notice').css({ - 'margin':'18px 0 29px 1.795%' + 'margin':'18px 0 29px 1.795%' }); + + $('#form_notice label, h1').css({'display': 'none'}); + + $('.notices li:first-child').css({'border-top':'none'}); } } From 7c335c28da886f48439ad648bd5ab4957152f140 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:21:49 +0000 Subject: [PATCH 16/73] Updated window resize --- plugins/Realtime/realtimeupdate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index bcbf1ba287..984c1bf55e 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -139,12 +139,12 @@ RealtimeUpdate = { initPopupWindow: function() { - window.resizeTo(575, 640); + window.resizeTo(500, 550); $('address').hide(); $('#content').css({'width':'92%'}); $('#form_notice').css({ - 'margin':'18px 0 29px 1.795%' + 'margin':'18px 0 29px 1.795%', }); $('#form_notice label, h1').css({'display': 'none'}); From 3bc55e7b8bff2fe331371333de9ff4f96c8584d2 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:22:56 +0000 Subject: [PATCH 17/73] Reduced form_notice margin bottom --- plugins/Realtime/realtimeupdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 984c1bf55e..ad519158b0 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -144,7 +144,7 @@ RealtimeUpdate = { $('#content').css({'width':'92%'}); $('#form_notice').css({ - 'margin':'18px 0 29px 1.795%', + 'margin':'18px 0 18px 1.795%', }); $('#form_notice label, h1').css({'display': 'none'}); From c66a884ff5cec1e58a7ba40f310badd3f108d9a5 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:26:01 +0000 Subject: [PATCH 18/73] Increated content width --- plugins/Realtime/realtimeupdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index ad519158b0..965fea9926 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -141,7 +141,7 @@ RealtimeUpdate = { { window.resizeTo(500, 550); $('address').hide(); - $('#content').css({'width':'92%'}); + $('#content').css({'width':'93.5%'}); $('#form_notice').css({ 'margin':'18px 0 18px 1.795%', From 8904f0f67dc8ab79b07d95452171a1d2b0af5efc Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:38:40 +0000 Subject: [PATCH 19/73] Removing only notie_data-text label from view --- plugins/Realtime/realtimeupdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 965fea9926..fa0334881b 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -147,7 +147,7 @@ RealtimeUpdate = { 'margin':'18px 0 18px 1.795%', }); - $('#form_notice label, h1').css({'display': 'none'}); + $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'}); $('.notices li:first-child').css({'border-top':'none'}); } From 3bba45102130e01032163f40e52005744623c686 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:40:35 +0000 Subject: [PATCH 20/73] Aligning notice_data-attach from top --- plugins/Realtime/realtimeupdate.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index fa0334881b..86fb01a5d9 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -150,6 +150,8 @@ RealtimeUpdate = { $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'}); $('.notices li:first-child').css({'border-top':'none'}); + + $('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'}); } } From 7466887a2f6e9d8f5f45a8b2e92e2147c572864c Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:43:40 +0000 Subject: [PATCH 21/73] Adjusted form_notice width --- plugins/Realtime/realtimeupdate.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 86fb01a5d9..b791f4a2ab 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -145,6 +145,8 @@ RealtimeUpdate = { $('#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'}); From 22332555cf5eb920d6f95eced76446cf189d6f54 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 12:59:01 +0000 Subject: [PATCH 22/73] Aligned notice_data-attach input --- plugins/Realtime/realtimeupdate.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index b791f4a2ab..015c004397 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -154,6 +154,11 @@ RealtimeUpdate = { $('.notices li:first-child').css({'border-top':'none'}); $('#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' + }); } } From 60335fcbdf7b2ae4d27e7d413e7f5f46f61feda5 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 14:06:39 +0000 Subject: [PATCH 23/73] Draw a line to indicate new (unread) notice in a timeline since window blur. Inspired by Pidgin's Markerline plugin. --- plugins/Realtime/realtimeupdate.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 015c004397..b5f78e4163 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -14,6 +14,18 @@ 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) @@ -151,7 +163,7 @@ RealtimeUpdate = { $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'}); - $('.notices li:first-child').css({'border-top':'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'}); From 3694058976fca36edf2d7f43a75ffc74f0a7c672 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 27 Sep 2009 14:24:31 +0000 Subject: [PATCH 24/73] Changed terminology for poping a window --- plugins/Realtime/realtimeupdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index b5f78e4163..4cd68a816b 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -125,7 +125,7 @@ RealtimeUpdate = { addPopup: function(url, timeline, iconurl) { - $('#content').prepend(''); + $('#content').prepend(''); $('#realtime_timeline').css({ 'margin':'0 0 18px 0', From 3ff8514f5ed8dac381cf24d9de9a25dcfa20af77 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 26 Sep 2009 17:14:10 -0700 Subject: [PATCH 25/73] Fix URL linkification test cases for addition of 'title' attribution with long URL in f3c8fccc After removing 103 false positives, this leaves 4 actually broken tests, showing two failure modes for mail links: * 'mail without mailto' formatting shortcut in common_linkify didn't get the 'title' attribute added with the other URLs * links including mailto: protocol are being incorrectly expanded to http: protocol in the long URL --- tests/URLDetectionTest.php | 218 ++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/tests/URLDetectionTest.php b/tests/URLDetectionTest.php index 1c3f7cd96f..a7cdcaa242 100644 --- a/tests/URLDetectionTest.php +++ b/tests/URLDetectionTest.php @@ -28,69 +28,69 @@ 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 http://www.somesite.com/xyz/35637563@N00/52803365/ link'), + 'link http://www.somesite.com/xyz/35637563@N00/52803365/ link'), array('http://127.0.0.1', - 'http://127.0.0.1'), + 'http://127.0.0.1'), array('127.0.0.1', - '127.0.0.1'), + '127.0.0.1'), array('127.0.0.1:99', - '127.0.0.1:99'), + '127.0.0.1:99'), array('127.0.0.1/Name:test.php', - '127.0.0.1/Name:test.php'), + '127.0.0.1/Name:test.php'), array('127.0.0.1/~test', - '127.0.0.1/~test'), + '127.0.0.1/~test'), array('127.0.0.1/+test', - '127.0.0.1/+test'), + '127.0.0.1/+test'), array('127.0.0.1/$test', - '127.0.0.1/$test'), + '127.0.0.1/$test'), array('127.0.0.1/\'test', - '127.0.0.1/\'test'), + '127.0.0.1/\'test'), array('127.0.0.1/"test', - '127.0.0.1/"test'), + '127.0.0.1/"test'), array('127.0.0.1/-test', - '127.0.0.1/-test'), + '127.0.0.1/-test'), array('127.0.0.1/_test', - '127.0.0.1/_test'), + '127.0.0.1/_test'), array('127.0.0.1/!test', - '127.0.0.1/!test'), + '127.0.0.1/!test'), array('127.0.0.1/*test', - '127.0.0.1/*test'), + '127.0.0.1/*test'), array('127.0.0.1/test%20stuff', - '127.0.0.1/test%20stuff'), + '127.0.0.1/test%20stuff'), array('http://[::1]:99/test.php', - 'http://[::1]:99/test.php'), + 'http://[::1]:99/test.php'), array('http://::1/test.php', - 'http://::1/test.php'), + 'http://::1/test.php'), array('http://::1', - 'http://::1'), + 'http://::1'), array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php', - '2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php'), + '2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php'), array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php', - '[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php'), + '[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php'), array('2001:4978:1b5:0:21d:e0ff:fe66:59ab', - '2001:4978:1b5:0:21d:e0ff:fe66:59ab'), + '2001:4978:1b5:0:21d:e0ff:fe66:59ab'), array('http://127.0.0.1', - 'http://127.0.0.1'), + 'http://127.0.0.1'), array('example.com', - 'example.com'), + 'example.com'), array('example.com', - 'example.com'), + 'example.com'), array('http://example.com', - 'http://example.com'), + 'http://example.com'), array('http://example.com.', - 'http://example.com.'), + 'http://example.com.'), array('/var/lib/example.so', '/var/lib/example.so'), array('example', 'example'), array('user@example.com', - 'user@example.com'), + 'user@example.com'), array('user_name+other@example.com', - 'user_name+other@example.com'), + 'user_name+other@example.com'), array('mailto:user@example.com', - 'mailto:user@example.com'), + 'mailto:user@example.com'), array('mailto:user@example.com?subject=test', - 'mailto:user@example.com?subject=test'), + 'mailto:user@example.com?subject=test'), array('#example', '#'), array('#example.com', @@ -98,165 +98,165 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('#.net', '#'), array('http://example', - 'http://example'), + 'http://example'), array('http://3xampl3', - 'http://3xampl3'), + 'http://3xampl3'), array('http://example/', - 'http://example/'), + 'http://example/'), array('http://example/path', - 'http://example/path'), + 'http://example/path'), array('http://example.com', - 'http://example.com'), + 'http://example.com'), array('https://example.com', - 'https://example.com'), + 'https://example.com'), array('ftp://example.com', - 'ftp://example.com'), + 'ftp://example.com'), array('ftps://example.com', - 'ftps://example.com'), + 'ftps://example.com'), array('http://user@example.com', - 'http://user@example.com'), + 'http://user@example.com'), array('http://user:pass@example.com', - 'http://user:pass@example.com'), + 'http://user:pass@example.com'), array('http://example.com:8080', - 'http://example.com:8080'), + 'http://example.com:8080'), array('http://example.com:8080/test.php', - 'http://example.com:8080/test.php'), + 'http://example.com:8080/test.php'), array('example.com:8080/test.php', - 'example.com:8080/test.php'), + 'example.com:8080/test.php'), array('http://www.example.com', - 'http://www.example.com'), + 'http://www.example.com'), array('http://example.com/', - 'http://example.com/'), + 'http://example.com/'), array('http://example.com/path', - 'http://example.com/path'), + 'http://example.com/path'), array('http://example.com/path.html', - 'http://example.com/path.html'), + 'http://example.com/path.html'), array('http://example.com/path.html#fragment', - 'http://example.com/path.html#fragment'), + 'http://example.com/path.html#fragment'), array('http://example.com/path.php?foo=bar&bar=foo', - 'http://example.com/path.php?foo=bar&bar=foo'), + 'http://example.com/path.php?foo=bar&bar=foo'), array('http://example.com.', - 'http://example.com.'), + 'http://example.com.'), array('http://müllärör.de', - 'http://müllärör.de'), + 'http://müllärör.de'), array('http://ﺱﺲﺷ.com', - 'http://ﺱﺲﺷ.com'), + 'http://ﺱﺲﺷ.com'), array('http://сделаткартинки.com', - 'http://сделаткартинки.com'), + 'http://сделаткартинки.com'), array('http://tūdaliņ.lv', - 'http://tūdaliņ.lv'), + 'http://tūdaliņ.lv'), array('http://brændendekærlighed.com', - 'http://brændendekærlighed.com'), + 'http://brændendekærlighed.com'), array('http://あーるいん.com', - 'http://あーるいん.com'), + 'http://あーるいん.com'), array('http://예비교사.com', - 'http://예비교사.com'), + 'http://예비교사.com'), array('http://example.com.', - 'http://example.com.'), + 'http://example.com.'), array('http://example.com?', - 'http://example.com?'), + 'http://example.com?'), array('http://example.com!', - 'http://example.com!'), + 'http://example.com!'), array('http://example.com,', - 'http://example.com,'), + 'http://example.com,'), array('http://example.com;', - 'http://example.com;'), + 'http://example.com;'), array('http://example.com:', - 'http://example.com:'), + 'http://example.com:'), array('\'http://example.com\'', - '\'http://example.com\''), + '\'http://example.com\''), array('"http://example.com"', - '"http://example.com"'), + '"http://example.com"'), array('http://example.com', - 'http://example.com'), + 'http://example.com'), array('(http://example.com)', - '(http://example.com)'), + '(http://example.com)'), array('[http://example.com]', - '[http://example.com]'), + '[http://example.com]'), array('', - '<http://example.com>'), + '<http://example.com>'), array('http://example.com/path/(foo)/bar', - 'http://example.com/path/(foo)/bar'), + 'http://example.com/path/(foo)/bar'), array('http://example.com/path/[foo]/bar', - 'http://example.com/path/[foo]/bar'), + 'http://example.com/path/[foo]/bar'), array('http://example.com/path/foo/(bar)', - 'http://example.com/path/foo/(bar)'), + 'http://example.com/path/foo/(bar)'), //Not a valid url - urls cannot contain unencoded square brackets array('http://example.com/path/foo/[bar]', - 'http://example.com/path/foo/[bar]'), + 'http://example.com/path/foo/[bar]'), array('Hey, check out my cool site http://example.com okay?', - 'Hey, check out my cool site http://example.com okay?'), + 'Hey, check out my cool site http://example.com okay?'), array('What about parens (e.g. http://example.com/path/foo/(bar))?', - 'What about parens (e.g. http://example.com/path/foo/(bar))?'), + 'What about parens (e.g. http://example.com/path/foo/(bar))?'), array('What about parens (e.g. http://example.com/path/foo/(bar)?', - 'What about parens (e.g. http://example.com/path/foo/(bar)?'), + 'What about parens (e.g. http://example.com/path/foo/(bar)?'), array('What about parens (e.g. http://example.com/path/foo/(bar).)?', - 'What about parens (e.g. http://example.com/path/foo/(bar).)?'), + 'What about parens (e.g. http://example.com/path/foo/(bar).)?'), //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. http://example.com/path/(foo,bar)?'), + 'What about parens (e.g. http://example.com/path/(foo,bar)?'), array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?', - 'Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?'), + 'Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?'), array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?', - 'Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?'), + 'Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?'), array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?', - 'Unbalanced too (e.g. http://example.com/path/foo/((((bar)?'), + 'Unbalanced too (e.g. http://example.com/path/foo/((((bar)?'), array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?', - 'Unbalanced too (e.g. http://example.com/path/foo/(bar))))?'), + 'Unbalanced too (e.g. http://example.com/path/foo/(bar))))?'), array('example.com', - 'example.com'), + 'example.com'), array('example.org', - 'example.org'), + 'example.org'), array('example.co.uk', - 'example.co.uk'), + 'example.co.uk'), array('www.example.co.uk', - 'www.example.co.uk'), + 'www.example.co.uk'), array('farm1.images.example.co.uk', - 'farm1.images.example.co.uk'), + 'farm1.images.example.co.uk'), array('example.museum', - 'example.museum'), + 'example.museum'), array('example.travel', - 'example.travel'), + 'example.travel'), array('example.com.', - 'example.com.'), + 'example.com.'), array('example.com?', - 'example.com?'), + 'example.com?'), array('example.com!', - 'example.com!'), + 'example.com!'), array('example.com,', - 'example.com,'), + 'example.com,'), array('example.com;', - 'example.com;'), + 'example.com;'), array('example.com:', - 'example.com:'), + 'example.com:'), array('\'example.com\'', - '\'example.com\''), + '\'example.com\''), array('"example.com"', - '"example.com"'), + '"example.com"'), array('example.com', - 'example.com'), + 'example.com'), array('(example.com)', - '(example.com)'), + '(example.com)'), array('[example.com]', - '[example.com]'), + '[example.com]'), array('', - '<example.com>'), + '<example.com>'), array('Hey, check out my cool site example.com okay?', - 'Hey, check out my cool site example.com okay?'), + 'Hey, check out my cool site example.com okay?'), array('Hey, check out my cool site example.com.I made it.', - 'Hey, check out my cool site example.com.I made it.'), + 'Hey, check out my cool site example.com.I made it.'), array('Hey, check out my cool site example.com.Funny thing...', - 'Hey, check out my cool site example.com.Funny thing...'), + 'Hey, check out my cool site example.com.Funny thing...'), array('Hey, check out my cool site example.com.You will love it.', - 'Hey, check out my cool site example.com.You will love it.'), + 'Hey, check out my cool site example.com.You will love it.'), array('What about parens (e.g. example.com/path/foo/(bar))?', - 'What about parens (e.g. example.com/path/foo/(bar))?'), + 'What about parens (e.g. example.com/path/foo/(bar))?'), array('What about parens (e.g. example.com/path/foo/(bar)?', - 'What about parens (e.g. example.com/path/foo/(bar)?'), + 'What about parens (e.g. example.com/path/foo/(bar)?'), array('What about parens (e.g. example.com/path/foo/(bar).)?', - 'What about parens (e.g. example.com/path/foo/(bar).)?'), + 'What about parens (e.g. example.com/path/foo/(bar).)?'), array('What about parens (e.g. example.com/path/(foo,bar)?', - 'What about parens (e.g. example.com/path/(foo,bar)?'), + 'What about parens (e.g. example.com/path/(foo,bar)?'), array('file.ext', 'file.ext'), array('file.html', From fc2426d7ce33bba0e1ad4dfc1ed9af7749695b20 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Sun, 27 Sep 2009 16:52:15 -0400 Subject: [PATCH 26/73] Fix some bugs in the URL linkification, and fixed the unit test. --- classes/File.php | 8 +- classes/File_redirection.php | 3 + lib/util.php | 23 +++--- tests/HashTagDetectionTests.php | 1 + tests/URLDetectionTest.php | 131 ++++++++++++++++---------------- 5 files changed, 90 insertions(+), 76 deletions(-) diff --git a/classes/File.php b/classes/File.php index 9758cf7f55..e04a9d5255 100644 --- a/classes/File.php +++ b/classes/File.php @@ -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); - $redir_url = $redir_data['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); diff --git a/classes/File_redirection.php b/classes/File_redirection.php index 76b18f672d..79052bf7d3 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -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); diff --git a/lib/util.php b/lib/util.php index 56753debe0..d249b154fc 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; diff --git a/tests/HashTagDetectionTests.php b/tests/HashTagDetectionTests.php index aeac4a5e3f..483d7135e1 100644 --- a/tests/HashTagDetectionTests.php +++ b/tests/HashTagDetectionTests.php @@ -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'; diff --git a/tests/URLDetectionTest.php b/tests/URLDetectionTest.php index a7cdcaa242..45203bf6e3 100644 --- a/tests/URLDetectionTest.php +++ b/tests/URLDetectionTest.php @@ -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'; @@ -30,11 +31,11 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link', 'link http://www.somesite.com/xyz/35637563@N00/52803365/ link'), array('http://127.0.0.1', - 'http://127.0.0.1'), + 'http://127.0.0.1'), array('127.0.0.1', - '127.0.0.1'), + '127.0.0.1'), array('127.0.0.1:99', - '127.0.0.1:99'), + '127.0.0.1:99'), array('127.0.0.1/Name:test.php', '127.0.0.1/Name:test.php'), array('127.0.0.1/~test', @@ -62,23 +63,23 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('http://::1/test.php', 'http://::1/test.php'), array('http://::1', - 'http://::1'), + 'http://::1'), array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php', '2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php'), array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php', '[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php'), array('2001:4978:1b5:0:21d:e0ff:fe66:59ab', - '2001:4978:1b5:0:21d:e0ff:fe66:59ab'), + '2001:4978:1b5:0:21d:e0ff:fe66:59ab'), array('http://127.0.0.1', - 'http://127.0.0.1'), + 'http://127.0.0.1'), array('example.com', - 'example.com'), + 'example.com'), array('example.com', - 'example.com'), + 'example.com'), array('http://example.com', - 'http://example.com'), + 'http://example.com'), array('http://example.com.', - 'http://example.com.'), + 'http://example.com.'), array('/var/lib/example.so', '/var/lib/example.so'), array('example', @@ -91,6 +92,8 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase 'mailto:user@example.com'), array('mailto:user@example.com?subject=test', 'mailto:user@example.com?subject=test'), + array('xmpp:user@example.com', + 'xmpp:user@example.com'), array('#example', '#'), array('#example.com', @@ -98,33 +101,33 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('#.net', '#'), array('http://example', - 'http://example'), + 'http://example'), array('http://3xampl3', - 'http://3xampl3'), + 'http://3xampl3'), array('http://example/', 'http://example/'), array('http://example/path', 'http://example/path'), array('http://example.com', - 'http://example.com'), + 'http://example.com'), array('https://example.com', - 'https://example.com'), + 'https://example.com'), array('ftp://example.com', - 'ftp://example.com'), + 'ftp://example.com'), array('ftps://example.com', - 'ftps://example.com'), + 'ftps://example.com'), array('http://user@example.com', - 'http://user@example.com'), + 'http://user@example.com'), array('http://user:pass@example.com', - 'http://user:pass@example.com'), + 'http://user:pass@example.com'), array('http://example.com:8080', - 'http://example.com:8080'), + 'http://example.com:8080'), array('http://example.com:8080/test.php', 'http://example.com:8080/test.php'), array('example.com:8080/test.php', 'example.com:8080/test.php'), array('http://www.example.com', - 'http://www.example.com'), + 'http://www.example.com'), array('http://example.com/', 'http://example.com/'), array('http://example.com/path', @@ -136,45 +139,45 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('http://example.com/path.php?foo=bar&bar=foo', 'http://example.com/path.php?foo=bar&bar=foo'), array('http://example.com.', - 'http://example.com.'), + 'http://example.com.'), array('http://müllärör.de', - 'http://müllärör.de'), + 'http://müllärör.de'), array('http://ﺱﺲﺷ.com', - 'http://ﺱﺲﺷ.com'), + 'http://ﺱﺲﺷ.com'), array('http://сделаткартинки.com', - 'http://сделаткартинки.com'), + 'http://сделаткартинки.com'), array('http://tūdaliņ.lv', - 'http://tūdaliņ.lv'), + 'http://tūdaliņ.lv'), array('http://brændendekærlighed.com', - 'http://brændendekærlighed.com'), + 'http://brændendekærlighed.com'), array('http://あーるいん.com', - 'http://あーるいん.com'), + 'http://あーるいん.com'), array('http://예비교사.com', - 'http://예비교사.com'), + 'http://예비교사.com'), array('http://example.com.', - 'http://example.com.'), + 'http://example.com.'), array('http://example.com?', - 'http://example.com?'), + 'http://example.com?'), array('http://example.com!', - 'http://example.com!'), + 'http://example.com!'), array('http://example.com,', - 'http://example.com,'), + 'http://example.com,'), array('http://example.com;', - 'http://example.com;'), + 'http://example.com;'), array('http://example.com:', - 'http://example.com:'), + 'http://example.com:'), array('\'http://example.com\'', - '\'http://example.com\''), + '\'http://example.com\''), array('"http://example.com"', - '"http://example.com"'), + '"http://example.com"'), array('http://example.com', - 'http://example.com'), + 'http://example.com'), array('(http://example.com)', - '(http://example.com)'), + '(http://example.com)'), array('[http://example.com]', - '[http://example.com]'), + '[http://example.com]'), array('', - '<http://example.com>'), + '<http://example.com>'), array('http://example.com/path/(foo)/bar', 'http://example.com/path/(foo)/bar'), array('http://example.com/path/[foo]/bar', @@ -185,7 +188,7 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('http://example.com/path/foo/[bar]', 'http://example.com/path/foo/[bar]'), array('Hey, check out my cool site http://example.com okay?', - 'Hey, check out my cool site http://example.com okay?'), + 'Hey, check out my cool site http://example.com okay?'), array('What about parens (e.g. http://example.com/path/foo/(bar))?', 'What about parens (e.g. http://example.com/path/foo/(bar))?'), array('What about parens (e.g. http://example.com/path/foo/(bar)?', @@ -204,51 +207,51 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?', 'Unbalanced too (e.g. http://example.com/path/foo/(bar))))?'), array('example.com', - 'example.com'), + 'example.com'), array('example.org', - 'example.org'), + 'example.org'), array('example.co.uk', - 'example.co.uk'), + 'example.co.uk'), array('www.example.co.uk', - 'www.example.co.uk'), + 'www.example.co.uk'), array('farm1.images.example.co.uk', - 'farm1.images.example.co.uk'), + 'farm1.images.example.co.uk'), array('example.museum', - 'example.museum'), + 'example.museum'), array('example.travel', - 'example.travel'), + 'example.travel'), array('example.com.', - 'example.com.'), + 'example.com.'), array('example.com?', - 'example.com?'), + 'example.com?'), array('example.com!', - 'example.com!'), + 'example.com!'), array('example.com,', - 'example.com,'), + 'example.com,'), array('example.com;', - 'example.com;'), + 'example.com;'), array('example.com:', - 'example.com:'), + 'example.com:'), array('\'example.com\'', - '\'example.com\''), + '\'example.com\''), array('"example.com"', - '"example.com"'), + '"example.com"'), array('example.com', - 'example.com'), + 'example.com'), array('(example.com)', - '(example.com)'), + '(example.com)'), array('[example.com]', - '[example.com]'), + '[example.com]'), array('', - '<example.com>'), + '<example.com>'), array('Hey, check out my cool site example.com okay?', - 'Hey, check out my cool site example.com okay?'), + 'Hey, check out my cool site example.com okay?'), array('Hey, check out my cool site example.com.I made it.', - 'Hey, check out my cool site example.com.I made it.'), + 'Hey, check out my cool site example.com.I made it.'), array('Hey, check out my cool site example.com.Funny thing...', - 'Hey, check out my cool site example.com.Funny thing...'), + 'Hey, check out my cool site example.com.Funny thing...'), array('Hey, check out my cool site example.com.You will love it.', - 'Hey, check out my cool site example.com.You will love it.'), + 'Hey, check out my cool site example.com.You will love it.'), array('What about parens (e.g. example.com/path/foo/(bar))?', 'What about parens (e.g. example.com/path/foo/(bar))?'), array('What about parens (e.g. example.com/path/foo/(bar)?', From a8d1b7e9c26b4449a4a1e0e250f9b6766b2d8e62 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 27 Sep 2009 21:10:17 -0400 Subject: [PATCH 27/73] Merge DeleteAction class into DeletenoticeAction The DeleteAction class checked for notice information, and only had one subclass: DeletenoticeAction. I couldn't figure out any other class that would subclass it, so I combined the two into a single class. --- actions/deletenotice.php | 37 +++++++++++++++++--- lib/deleteaction.php | 74 ---------------------------------------- 2 files changed, 33 insertions(+), 78 deletions(-) delete mode 100644 lib/deleteaction.php diff --git a/actions/deletenotice.php b/actions/deletenotice.php index 3d040f2fa9..617fa9c17a 100644 --- a/actions/deletenotice.php +++ b/actions/deletenotice.php @@ -32,15 +32,44 @@ 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 $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) { + common_user_error(_('Can\'t delete this notice.')); + exit; + } // XXX: Ajax! if ($_SERVER['REQUEST_METHOD'] == 'POST') { diff --git a/lib/deleteaction.php b/lib/deleteaction.php deleted file mode 100644 index f702820c61..0000000000 --- a/lib/deleteaction.php +++ /dev/null @@ -1,74 +0,0 @@ -. - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @author Sarven Capadisli - * @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; - } - } - -} From 6c069312e2911d3b2fe54d051354f579fde7bb63 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 15 Sep 2009 15:28:11 -0400 Subject: [PATCH 28/73] user rights --- classes/User.php | 26 ++++++++++++++++++ lib/right.php | 50 ++++++++++++++++++++++++++++++++++ tests/UserRightsTest.php | 59 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 lib/right.php create mode 100644 tests/UserRightsTest.php diff --git a/classes/User.php b/classes/User.php index 5e74c7fde4..bea81af4d2 100644 --- a/classes/User.php +++ b/classes/User.php @@ -711,4 +711,30 @@ 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) + { + switch ($right) + { + case Right::deleteOthersNotice: + return $this->hasRole('moderator'); + break; + default: + $result = false; + Event::handle('UserRightsCheck', array($this, &$result)); + return $result; + } + } } diff --git a/lib/right.php b/lib/right.php new file mode 100644 index 0000000000..4e0096d46a --- /dev/null +++ b/lib/right.php @@ -0,0 +1,50 @@ +. + * + * @category Authorization + * @package StatusNet + * @author Evan Prodromou + * @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 + * @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/tests/UserRightsTest.php b/tests/UserRightsTest.php new file mode 100644 index 0000000000..6544ee53d7 --- /dev/null +++ b/tests/UserRightsTest.php @@ -0,0 +1,59 @@ +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)); + } +} \ No newline at end of file From 38345d078343d4631eab2c883a39d87380f7b1af Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 16 Sep 2009 21:08:44 -0400 Subject: [PATCH 29/73] let hooks override standard user rights --- classes/User.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/classes/User.php b/classes/User.php index bea81af4d2..3f7ed09bb7 100644 --- a/classes/User.php +++ b/classes/User.php @@ -726,15 +726,18 @@ class User extends Memcached_DataObject function hasRight($right) { - switch ($right) - { - case Right::deleteOthersNotice: - return $this->hasRole('moderator'); - break; - default: - $result = false; - Event::handle('UserRightsCheck', array($this, &$result)); - return $result; + $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; } } From ee236e68df8a8b7ee7917fd60ef36b57c0bd64db Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 27 Sep 2009 21:05:29 -0400 Subject: [PATCH 30/73] show delete button when user has deleteOthersNotice right --- lib/noticelist.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/noticelist.php b/lib/noticelist.php index c2ff7c26b3..6c296f82a7 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, From ee9856c452a7e54994c30cd9138dd6faa2107001 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 27 Sep 2009 21:14:49 -0400 Subject: [PATCH 31/73] moderator can delete another user's notice --- actions/deletenotice.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actions/deletenotice.php b/actions/deletenotice.php index 617fa9c17a..4a48a9c346 100644 --- a/actions/deletenotice.php +++ b/actions/deletenotice.php @@ -66,7 +66,8 @@ class DeletenoticeAction extends Action if (!common_logged_in()) { common_user_error(_('Not logged in.')); exit; - } else if ($this->notice->profile_id != $this->user_profile->id) { + } else if ($this->notice->profile_id != $this->user_profile->id && + !$this->user->hasRight(Right::deleteOthersNotice)) { common_user_error(_('Can\'t delete this notice.')); exit; } From 6b7a007ef2e3ea64be547923b97f08670dc13d14 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 27 Sep 2009 20:21:16 -0700 Subject: [PATCH 32/73] Forgot to add home_timeline to the list of methods that only require bareauth. --- actions/api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/api.php b/actions/api.php index c236378bcb..3705d035c4 100644 --- a/actions/api.php +++ b/actions/api.php @@ -142,6 +142,7 @@ class ApiAction extends Action static $bareauth = array('statuses/user_timeline', 'statuses/friends_timeline', + 'statuses/home_timeline', 'statuses/friends', 'statuses/replies', 'statuses/mentions', From 4e6c7302072eb6e11ae0025795a7a96fb28f2f29 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 27 Sep 2009 20:21:16 -0700 Subject: [PATCH 33/73] Forgot to add home_timeline to the list of methods that only require bareauth. --- actions/api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/api.php b/actions/api.php index d570bb0174..1bc90de110 100644 --- a/actions/api.php +++ b/actions/api.php @@ -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', From 155ba6c103b3672656937ad36bec02cb9c7834e5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Sep 2009 09:12:44 -0400 Subject: [PATCH 34/73] stop overwriting created timestamp on group edit --- actions/editgroup.php | 1 - 1 file changed, 1 deletion(-) diff --git a/actions/editgroup.php b/actions/editgroup.php index e7ba836a01..b8dac31cb1 100644 --- a/actions/editgroup.php +++ b/actions/editgroup.php @@ -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); From 0a57d1ccee1af8570d4c83934d9ab99fa1a1dc37 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Sep 2009 17:16:07 -0400 Subject: [PATCH 35/73] change string return from Notice::saveNew to exceptions --- classes/Notice.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index f3fa9af781..93d5de7908 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -153,30 +153,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 +222,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 +247,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.')); } } From 89ac81c34464b2fc4f54b643d0d95d12bac765ab Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Sep 2009 17:25:52 -0400 Subject: [PATCH 36/73] remove string-checks from code using Notice::saveNew() --- actions/newnotice.php | 7 ------- actions/twitapistatuses.php | 5 ----- lib/facebookaction.php | 10 +++++----- lib/oauthstore.php | 5 +---- scripts/maildaemon.php | 9 +++++---- scripts/xmppdaemon.php | 11 +++++++---- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index 23ec2a1b58..d5b0332f48 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -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); } diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 2f10ff966c..87043b1821 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -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; } diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 411f795945..3f3a8d3b09 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/oauthstore.php b/lib/oauthstore.php index e69a00f55f..d617a7df7e 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/scripts/maildaemon.php b/scripts/maildaemon.php index 5705cfd50e..586bef624e 100755 --- a/scripts/maildaemon.php +++ b/scripts/maildaemon.php @@ -260,10 +260,11 @@ class MailerDaemon function add_notice($user, $msg, $fileRecords) { - $notice = Notice::saveNew($user->id, $msg, 'mail'); - if (is_string($notice)) { - $this->log(LOG_ERR, $notice); - return $notice; + try { + $notice = Notice::saveNew($user->id, $msg, 'mail'); + } catch (Exception $e) { + $this->log(LOG_ERR, $e->getMessage()); + return $e->getMessage(); } foreach($fileRecords as $fileRecord){ $this->attachFile($notice, $fileRecord); diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php index 1b1aec3e6e..b2efc07c38 100755 --- a/scripts/xmppdaemon.php +++ b/scripts/xmppdaemon.php @@ -323,12 +323,15 @@ class XMPPDaemon extends Daemon mb_strlen($content_shortened))); return; } - $notice = Notice::saveNew($user->id, $content_shortened, 'xmpp'); - if (is_string($notice)) { - $this->log(LOG_ERR, $notice); - $this->from_site($user->jabber, $notice); + + try { + $notice = Notice::saveNew($user->id, $content_shortened, 'xmpp'); + } 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); From 5252c438040f071e0c61a9c93152dcf1aa382504 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Sep 2009 17:43:45 -0400 Subject: [PATCH 37/73] move HTTP error code strings to class variables --- lib/clienterroraction.php | 43 +++++++++++++++++---------------------- lib/error.php | 6 ++++-- lib/servererroraction.php | 19 +++++++---------- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/lib/clienterroraction.php b/lib/clienterroraction.php index 7d007a7567..1b98a10645 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/error.php b/lib/error.php index 0c521db081..6a9b76be11 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/servererroraction.php b/lib/servererroraction.php index c6400605ea..0993a63bca 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]; - } } From 5309910b9b4dd2533ff5b2190f90bf415fd20113 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Sep 2009 17:57:31 -0400 Subject: [PATCH 38/73] Twitter API returns server errors in preferred format --- actions/twitapistatuses.php | 2 +- lib/twitterapi.php | 56 ++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 5e2867ea81..41887a68f4 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -297,7 +297,7 @@ class TwitapistatusesAction extends TwitterapiAction $source, 1, $reply_to); if (is_string($notice)) { - $this->serverError($notice); + $this->serverError($notice, 500, $apidata['content-type']); return; } diff --git a/lib/twitterapi.php b/lib/twitterapi.php index 638efba241..3bac400e2f 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -501,7 +501,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); @@ -939,35 +939,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') { @@ -986,6 +967,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(); From eb85f16f773ff1df71d1af4fad85d40286d5f3a6 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 30 Sep 2009 10:37:46 +0000 Subject: [PATCH 39/73] Switched Doctype to XHTML 1.0 Strict (which best reflects the current grammar in use) --- lib/htmloutputter.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index aa01f6b1d9..9e3a5b305e 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -113,7 +113,9 @@ class HTMLOutputter extends XMLOutputter // Browsers don't like it when 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(); From 353f58c23149159306131b0819de713da6b69464 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 30 Sep 2009 10:51:59 +0000 Subject: [PATCH 40/73] Outputting UTF-8 charset in document header irrespective of mimetype. --- lib/htmloutputter.php | 2 +- lib/util.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 9e3a5b305e..99f956545b 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -106,7 +106,7 @@ class HTMLOutputter extends XMLOutputter } } - header('Content-Type: '.$type); + header('Content-Type: '.$type.'; charset=UTF-8'); $this->extraHeaders(); if( ! substr($type,0,strlen('text/html'))=='text/html' ){ diff --git a/lib/util.php b/lib/util.php index b831859e99..a069ccf7b3 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1148,7 +1148,7 @@ function common_negotiate_type($cprefs, $sprefs) } if ('text/html' === $besttype) { - return "text/html; charset=utf-8"; + return "text/html"; } return $besttype; } From 1e7df7fbab8a03468a1697240e92f67c82dadced Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 30 Sep 2009 10:53:04 +0000 Subject: [PATCH 41/73] Better check to see if the XML prolog should be outputted for XML documents i.e., if best mimetype is */*xml, then use the XML prolog. --- lib/htmloutputter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 99f956545b..64be745beb 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -109,8 +109,8 @@ class HTMLOutputter extends XMLOutputter header('Content-Type: '.$type.'; charset=UTF-8'); $this->extraHeaders(); - if( ! substr($type,0,strlen('text/html'))=='text/html' ){ - // Browsers don't like it when xw->startDocument('1.0', 'UTF-8'); } $this->xw->writeDTD('html', From 267ab67c8325243d176e1124f2024c7b08417f37 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 30 Sep 2009 12:22:55 +0000 Subject: [PATCH 42/73] Script no longer needed for Realtime plugin --- plugins/Realtime/jquery.getUrlParam.js | 72 -------------------------- 1 file changed, 72 deletions(-) delete mode 100644 plugins/Realtime/jquery.getUrlParam.js diff --git a/plugins/Realtime/jquery.getUrlParam.js b/plugins/Realtime/jquery.getUrlParam.js deleted file mode 100644 index e8f73eb478..0000000000 --- a/plugins/Realtime/jquery.getUrlParam.js +++ /dev/null @@ -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 Date: Wed, 30 Sep 2009 12:48:15 +0000 Subject: [PATCH 43/73] Relocated the button for pop up window for notice stream --- plugins/Realtime/realtimeupdate.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 4cd68a816b..3303d3a44f 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -125,14 +125,17 @@ RealtimeUpdate = { addPopup: function(url, timeline, iconurl) { - $('#content').prepend(''); + $('#notices_primary').css({'position':'relative'}); + $('#notices_primary').prepend(''); $('#realtime_timeline').css({ - 'margin':'0 0 18px 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', 'color':$("a").css("color"), From a57783de0214f061eca3ab65880f573e8668de03 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 30 Sep 2009 13:29:37 +0000 Subject: [PATCH 44/73] Timeout a little incase the notice item from XHR response is not appended to the page. --- plugins/Realtime/realtimeupdate.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index 3303d3a44f..11e466325e 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -30,19 +30,20 @@ RealtimeUpdate = { receive: function(data) { - id = data.id; + 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); - $("#notices_primary .notice:first").css({display:"none"}); - $("#notices_primary .notice:first").fadeIn(1000); - NoticeReply(); + // Don't add it if it already exists + if ($("#notice-"+id).length > 0) { + return; + } + + var noticeItem = RealtimeUpdate.makeNoticeItem(data); + $("#notices_primary .notices").prepend(noticeItem); + $("#notices_primary .notice:first").css({display:"none"}); + $("#notices_primary .notice:first").fadeIn(1000); + NoticeReply(); + }, 500); }, makeNoticeItem: function(data) From c5be2962ad6fa4f78a4892005bc6a342de89c5d0 Mon Sep 17 00:00:00 2001 From: Toby Inkster Date: Wed, 30 Sep 2009 13:12:17 +0100 Subject: [PATCH 45/73] FOAF for Groups. --- actions/foafgroup.php | 173 ++++++++++++++++++++++++++++++++++++++++++ actions/showgroup.php | 7 +- lib/router.php | 4 + 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 actions/foafgroup.php diff --git a/actions/foafgroup.php b/actions/foafgroup.php new file mode 100644 index 0000000000..f5fd7fe885 --- /dev/null +++ b/actions/foafgroup.php @@ -0,0 +1,173 @@ +. + * + * @category Mail + * @package StatusNet + * @author Evan Prodromou + * @author Toby Inkster + * @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'); + } + +} \ No newline at end of file diff --git a/actions/showgroup.php b/actions/showgroup.php index ff99497621..a67765ce58 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -345,7 +345,12 @@ class ShowgroupAction extends GroupDesignAction 'method' => 'timeline', 'argument' => $this->group->nickname.'.atom')), sprintf(_('Notice feed for %s group (Atom)'), - $this->group->nickname))); + $this->group->nickname)), + new Feed(Feed::FOAF, + common_local_url('foafgroup', + array('nickname' => $this->group->nickname)), + sprintf(_('FOAF for %s group'), + $this->group->nickname))); } /** diff --git a/lib/router.php b/lib/router.php index c18f273ed0..91f886bce1 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]+')); From cc776478e2ea8fc861fd3b4e8e878f7d6020c34e Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 1 Oct 2009 10:07:09 +0000 Subject: [PATCH 46/73] Revert "Outputting UTF-8 charset in document header irrespective of mimetype." This reverts commit 353f58c23149159306131b0819de713da6b69464. Even though outputting UTF-8 by default at all times is a good thing, it shouldn't be forced in startHTML(). --- lib/htmloutputter.php | 2 +- lib/util.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 64be745beb..c70f965376 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -106,7 +106,7 @@ class HTMLOutputter extends XMLOutputter } } - header('Content-Type: '.$type.'; charset=UTF-8'); + header('Content-Type: '.$type); $this->extraHeaders(); if (preg_match("/.*\/.*xml/", $type)) { diff --git a/lib/util.php b/lib/util.php index 44a3772200..d249b154fc 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1165,7 +1165,7 @@ function common_negotiate_type($cprefs, $sprefs) } if ('text/html' === $besttype) { - return "text/html"; + return "text/html; charset=utf-8"; } return $besttype; } From acc78972383c2346b5729192ab00c90c48c5b2a6 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 1 Oct 2009 12:27:02 +0000 Subject: [PATCH 47/73] Added hook for Aside container --- EVENTS.txt | 6 ++++++ lib/action.php | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/EVENTS.txt b/EVENTS.txt index 74923dcc0a..e0d4bbd061 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -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) diff --git a/lib/action.php b/lib/action.php index 02793f0694..71ceffe20d 100644 --- a/lib/action.php +++ b/lib/action.php @@ -525,7 +525,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'); } From b980f5e45b613d60e968e84b304ef9db260f24c2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 1 Oct 2009 15:00:54 -0400 Subject: [PATCH 48/73] add some more methods to Schema --- lib/schema.php | 203 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 184 insertions(+), 19 deletions(-) diff --git a/lib/schema.php b/lib/schema.php index f490756905..056c2093d6 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -193,32 +193,161 @@ class Schema return true; } - public function createIndex($name, $table, $columns) + 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; } - public function dropIndex($name, $table) + 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; } public function addColumn($table, $columndef) { - } + $sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef); - public function modifyColumn($table, $column, $columndef) - { - } + $res =& $this->conn->query($sql); - public function dropColumn($table, $column) - { - } - - public function ensureTable($name, $columns, $indices) - { - $def = $this->tableDef($name); - if (empty($def)) { - return $this->createTable($name, $columns, $indices); + if (PEAR::isError($res)) { + throw new Exception($res->getMessage()); } + + return true; + } + + 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; + } + + 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; + } + + public function ensureTable($tableName, $columns, $indices=null) + { + // 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, $indices); + } 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); + + 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; + } + + function _names($cds) + { + $names = array(); + + foreach ($cds as $cd) { + $names[] = $cd->name; + } + + return $names; + } + + function _byName($cds, $name) + { + foreach ($cds as $cd) { + if ($cd->name == $name) { + return $cd; + } + } + + return null; } function _columnSql($cd) @@ -257,16 +386,52 @@ class ColumnDef public $default; public $extra; - function __construct($name, $type, $size=null, $nullable=null, + function __construct($name, $type, $size=null, $nullable=true, $key=null, $default=null, $extra=null) { - $this->name = $name; - $this->type = $type; - $this->size = $size; + $this->name = strtolower($name); + $this->type = strtolower($type); + $this->size = $size+0; $this->nullable = $nullable; $this->key = $key; $this->default = $default; $this->extra = $extra; } + + function equals($other) + { + return ($this->name == $other->name && + $this->_typeMatch($other) && + $this->_defaultMatch($other) && + $this->_nullMatch($other) && + $this->key == $other->key); + } + + 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); + } + } + + function _defaultMatch($other) + { + return ((is_null($this->default) && is_null($other->default)) || + ($this->default == $other->default)); + } + + function _nullMatch($other) + { + return ((!is_null($this->default) && !is_null($other->default) && + $this->default == $other->default) || + ($this->nullable == $other->nullable)); + } } class IndexDef From d103522ff364098ed26305b31d1cb62f87de1318 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 1 Oct 2009 15:11:12 -0400 Subject: [PATCH 49/73] check the schema --- EVENTS.txt | 2 ++ README | 8 ++++++++ lib/common.php | 6 ++++++ lib/default.php | 3 ++- scripts/checkschema.php | 30 ++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 scripts/checkschema.php diff --git a/EVENTS.txt b/EVENTS.txt index e0d4bbd061..fbb2f36a7b 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -283,3 +283,5 @@ StartShowHeadElements: Right after the tag EndShowHeadElements: Right before the tag; put