]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch '0.9.x' into refactor-api
authorZach Copley <zach@status.net>
Wed, 30 Sep 2009 17:32:05 +0000 (10:32 -0700)
committerZach Copley <zach@status.net>
Wed, 30 Sep 2009 17:32:05 +0000 (10:32 -0700)
* 0.9.x: (39 commits)
  Timeout a little incase the notice item from XHR response is
  Relocated the button for pop up window for notice stream
  Script no longer needed for Realtime plugin
  Better check to see if the XML prolog should be outputted for XML
  Outputting UTF-8 charset in document header irrespective of mimetype.
  Switched Doctype to XHTML 1.0 Strict (which best reflects the current
  Twitter API returns server errors in preferred format
  move HTTP error code strings to class variables
  remove string-checks from code using Notice::saveNew()
  change string return from Notice::saveNew to exceptions
  stop overwriting created timestamp on group edit
  Forgot to add home_timeline to the list of methods that only require
  Forgot to add home_timeline to the list of methods that only require
  moderator can delete another user's notice
  show delete button when user has deleteOthersNotice right
  let hooks override standard user rights
  user rights
  Merge DeleteAction class into DeletenoticeAction
  Fix some bugs in the URL linkification, and fixed the unit test.
  Fix URL linkification test cases for addition of 'title' attribution with long URL in f3c8fccc
  ...

34 files changed:
EVENTS.txt
actions/api.php
actions/deletenotice.php
actions/editgroup.php
actions/newnotice.php
actions/twitapistatuses.php
classes/File.php
classes/File_redirection.php
classes/Notice.php
classes/User.php
lib/clienterroraction.php
lib/common.php
lib/default.php [new file with mode: 0644]
lib/deleteaction.php [deleted file]
lib/error.php
lib/facebookaction.php
lib/htmloutputter.php
lib/noticelist.php
lib/oauthstore.php
lib/right.php [new file with mode: 0644]
lib/servererroraction.php
lib/twitterapi.php
lib/util.php
plugins/PiwikAnalyticsPlugin.php
plugins/Realtime/RealtimePlugin.php
plugins/Realtime/jquery.getUrlParam.js [deleted file]
plugins/Realtime/realtimeupdate.js
scripts/createsim.php
scripts/maildaemon.php
scripts/xmppdaemon.php
tests/HashTagDetectionTests.php
tests/URLDetectionTest.php
tests/UserRightsTest.php [new file with mode: 0644]
theme/base/css/display.css

index fa25aabcd66208cf10c97feee0df1219ea88e14a..74923dcc0a8301132a34c09e4a0542ce215885ae 100644 (file)
@@ -194,6 +194,12 @@ StartShowExportData: just before showing the <div> with export data (feeds)
 EndShowExportData: just after showing the <div> with export data (feeds)
 - $action: action object being shown
 
+StartShowNoticeItem: just before showing the notice item
+- $action: action object being shown
+
+EndShowNoticeItem: just after showing the notice item
+- $action: action object being shown
+
 StartShowPageNotice: just before showing the page notice (instructions or error)
 - $action: action object being shown
 
index d570bb0174a093297f4fc2e6e903e32ccd2f224a..1bc90de1108cb2f385eb97c8ffbb145dc5e0d946 100644 (file)
@@ -160,6 +160,7 @@ class ApiAction extends Action
 
         static $bareauth = array('statuses/user_timeline',
                                  'statuses/friends_timeline',
+                                'statuses/home_timeline',
                                  'statuses/friends',
                                  'statuses/replies',
                                  'statuses/mentions',
index 3d040f2fa91ed7b7e736c5be7d744d61667aeaea..4a48a9c346cba2b9714e30184c65273d8ae56632 100644 (file)
@@ -32,15 +32,45 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
     exit(1);
 }
 
-require_once INSTALLDIR.'/lib/deleteaction.php';
-
-class DeletenoticeAction extends DeleteAction
+class DeletenoticeAction extends Action
 {
-    var $error = null;
+    var $error        = null;
+    var $user         = null;
+    var $notice       = null;
+    var $profile      = null;
+    var $user_profile = null;
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $this->user   = common_current_user();
+        $notice_id    = $this->trimmed('notice');
+        $this->notice = Notice::staticGet($notice_id);
+
+        if (!$this->notice) {
+            common_user_error(_('No such notice.'));
+            exit;
+        }
+
+        $this->profile      = $this->notice->getProfile();
+        $this->user_profile = $this->user->getProfile();
+
+        return true;
+    }
 
     function handle($args)
     {
         parent::handle($args);
+
+        if (!common_logged_in()) {
+            common_user_error(_('Not logged in.'));
+            exit;
+        } else if ($this->notice->profile_id != $this->user_profile->id &&
+                   !$this->user->hasRight(Right::deleteOthersNotice)) {
+            common_user_error(_('Can\'t delete this notice.'));
+            exit;
+        }
         // XXX: Ajax!
 
         if ($_SERVER['REQUEST_METHOD'] == 'POST') {
index 0c2dc8bdf89ef027141d09d38ae1de434696bfc7..5dd039f8a30c3dc55d4d64f9994890e5e1bfe8c2 100644 (file)
@@ -250,7 +250,6 @@ class EditgroupAction extends GroupDesignAction
         $this->group->homepage    = $homepage;
         $this->group->description = $description;
         $this->group->location    = $location;
-        $this->group->created     = common_sql_now();
 
         $result = $this->group->update($orig);
 
index 23ec2a1b5827c3aca92ecb4f20d36c7e6da10718..d5b0332f4878bd58984b0425614a802beb0d04f6 100644 (file)
@@ -255,13 +255,6 @@ class NewnoticeAction extends Action
         $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
                                   ($replyto == 'false') ? null : $replyto);
 
-        if (is_string($notice)) {
-            if (isset($filename)) {
-                $this->deleteFile($filename);
-            }
-            $this->clientError($notice);
-        }
-
         if (isset($mimetype)) {
             $this->attachFile($notice, $fileRecord);
         }
index 2f10ff966c8113a34477e4b7e2832945f447b385..87043b1821cb47672af710706b63c901014cd9bc 100644 (file)
@@ -297,11 +297,6 @@ class TwitapistatusesAction extends TwitterapiAction
                 html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'),
                     $source, 1, $reply_to);
 
-            if (is_string($notice)) {
-                $this->serverError($notice);
-                return;
-            }
-
             common_broadcast_notice($notice);
             $apidata['api_arg'] = $notice->id;
         }
index 9758cf7f5576a5db08150740032ba276994de0a1..e04a9d5255ad50c85c840e3563e58ed0017610b9 100644 (file)
@@ -94,7 +94,13 @@ class File extends Memcached_DataObject
             $file_redir = File_redirection::staticGet('url', $given_url);
             if (empty($file_redir)) {
                 $redir_data = File_redirection::where($given_url);
-                $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);
index 76b18f672d3e23d969b50f69052e29f6f08acf81..79052bf7d3e80ca6e5b9347ee2062e5e9cc8ad22 100644 (file)
@@ -79,6 +79,9 @@ class File_redirection extends Memcached_DataObject
             }
         }
 
+        if(strpos($short_url,'://') === false){
+            return $short_url;
+        }
         $curlh = File_redirection::_commonCurl($short_url, $redirs);
         // Don't include body in output
         curl_setopt($curlh, CURLOPT_NOBODY, true);
index f3fa9af7819c2a5d02d5d202bee38d3ca62645ff..93d5de79081d7395efc71e256e0d5cf4d8f29267 100644 (file)
@@ -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.'));
                 }
             }
 
index 5e74c7fde40835864d2ee81c3f7d20b263e927b0..3f7ed09bb7ae508c324ebec07f436060d6f40ca1 100644 (file)
@@ -711,4 +711,33 @@ class User extends Memcached_DataObject
 
         return true;
     }
+
+    /**
+     * Does this user have the right to do X?
+     *
+     * With our role-based authorization, this is merely a lookup for whether the user
+     * has a particular role. The implementation currently uses a switch statement
+     * to determine if the user has the pre-defined role to exercise the right. Future
+     * implementations may allow per-site roles, and different mappings of roles to rights.
+     *
+     * @param $right string Name of the right, usually a constant in class Right
+     * @return boolean whether the user has the right in question
+     */
+
+    function hasRight($right)
+    {
+        $result = false;
+        if (Event::handle('UserRightsCheck', array($this, $right, &$result))) {
+            switch ($right)
+            {
+             case Right::deleteOthersNotice:
+                $result = $this->hasRole('moderator');
+                break;
+             default:
+                $result = false;
+                break;
+            }
+        }
+        return $result;
+    }
 }
index 7d007a75675775ee35fa67dc89ea79acb2774426..1b98a1064570d6472bfc2c553925be5d15efb3a8 100644 (file)
@@ -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];
-    }
 }
index 194eb568f7d1a0ff2b7525599fd196443ee0bd78..58e208a4e92b98620fb540c7ffbafb67904d21d3 100644 (file)
@@ -53,6 +53,7 @@ require_once('DB/DataObject/Cast.php'); # for dates
 if (!function_exists('gettext')) {
     require_once("php-gettext/gettext.inc");
 }
+
 require_once(INSTALLDIR.'/lib/language.php');
 
 // This gets included before the config file, so that admin code and plugins
@@ -93,214 +94,17 @@ if (isset($path)) {
     null;
 }
 
-// default configuration, overwritten in config.php
+require_once(INSTALLDIR.'/lib/default.php');
+
+// Set config values initially to default values
 
-$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?
-        );
+$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 (file)
index 0000000..7af94d2
--- /dev/null
@@ -0,0 +1,232 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Default settings for core configuration
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Config
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008-9 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+$default =
+  array('site' =>
+        array('name' => 'Just another StatusNet microblog',
+              'server' => $_server,
+              'theme' => 'default',
+              'path' => $_path,
+              'logfile' => null,
+              'logo' => null,
+              'logdebug' => false,
+              'fancy' => false,
+              'locale_path' => INSTALLDIR.'/locale',
+              'language' => 'en_US',
+              'languages' => get_all_languages(),
+              'email' =>
+              array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
+              'broughtby' => null,
+              'timezone' => 'UTC',
+              'broughtbyurl' => null,
+              'closed' => false,
+              'inviteonly' => false,
+              'private' => false,
+              'ssl' => 'never',
+              'sslserver' => null,
+              'shorturllength' => 30,
+              'dupelimit' => 60, # default for same person saying the same thing
+              'textlimit' => 140,
+              ),
+        'db' =>
+        array('database' => 'YOU HAVE TO SET THIS IN config.php',
+              'schema_location' => INSTALLDIR . '/classes',
+              'class_location' => INSTALLDIR . '/classes',
+              'require_prefix' => 'classes/',
+              'class_prefix' => '',
+              'mirror' => null,
+              'utf8' => true,
+              'db_driver' => 'DB', # XXX: JanRain libs only work with DB
+              'quote_identifiers' => false,
+              'type' => 'mysql' ),
+        'syslog' =>
+        array('appname' => 'statusnet', # for syslog
+              'priority' => 'debug', # XXX: currently ignored
+              'facility' => LOG_USER),
+        'queue' =>
+        array('enabled' => false,
+              'subsystem' => 'db', # default to database, or 'stomp'
+              'stomp_server' => null,
+              'queue_basename' => 'statusnet',
+              'stomp_username' => null,
+              'stomp_password' => null,
+              ),
+        'license' =>
+        array('url' => 'http://creativecommons.org/licenses/by/3.0/',
+              'title' => 'Creative Commons Attribution 3.0',
+              'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'),
+        'mail' =>
+        array('backend' => 'mail',
+              'params' => null),
+        'nickname' =>
+        array('blacklist' => array(),
+              'featured' => array()),
+        'profile' =>
+        array('banned' => array(),
+              'biolimit' => null),
+        'avatar' =>
+        array('server' => null,
+              'dir' => INSTALLDIR . '/avatar/',
+              'path' => $_path . '/avatar/'),
+        'background' =>
+        array('server' => null,
+              'dir' => INSTALLDIR . '/background/',
+              'path' => $_path . '/background/'),
+        'public' =>
+        array('localonly' => true,
+              'blacklist' => array(),
+              'autosource' => array()),
+        'theme' =>
+        array('server' => null,
+              'dir' => null,
+              'path'=> null),
+        'throttle' =>
+        array('enabled' => false, // whether to throttle edits; false by default
+              'count' => 20, // number of allowed messages in timespan
+              'timespan' => 600), // timespan for throttling
+        'xmpp' =>
+        array('enabled' => false,
+              'server' => 'INVALID SERVER',
+              'port' => 5222,
+              'user' => 'update',
+              'encryption' => true,
+              'resource' => 'uniquename',
+              'password' => 'blahblahblah',
+              'host' => null, # only set if != server
+              'debug' => false, # print extra debug info
+              'public' => array()), # JIDs of users who want to receive the public stream
+        'invite' =>
+        array('enabled' => true),
+        'sphinx' =>
+        array('enabled' => false,
+              'server' => 'localhost',
+              'port' => 3312),
+        'tag' =>
+        array('dropoff' => 864000.0),
+        'popular' =>
+        array('dropoff' => 864000.0),
+        'daemon' =>
+        array('piddir' => '/var/run',
+              'user' => false,
+              'group' => false),
+        'emailpost' =>
+        array('enabled' => true),
+        'sms' =>
+        array('enabled' => true),
+        'twitter' =>
+        array('enabled' => true),
+        'twitterbridge' =>
+        array('enabled' => false),
+        'integration' =>
+        array('source' => 'StatusNet', # source attribute for Twitter
+              'taguri' => $_server.',2009'), # base for tag URIs
+       'twitter' =>
+       array('consumer_key'    => null,
+             'consumer_secret' => null),
+        'memcached' =>
+        array('enabled' => false,
+              'server' => 'localhost',
+              'base' => null,
+              'port' => 11211),
+               'ping' =>
+        array('notify' => array()),
+        'inboxes' =>
+        array('enabled' => true), # on by default for new sites
+        'newuser' =>
+        array('default' => null,
+              'welcome' => null),
+        'snapshot' =>
+        array('run' => 'web',
+              'frequency' => 10000,
+              'reporturl' => 'http://status.net/stats/report'),
+        'attachments' =>
+        array('server' => null,
+              'dir' => INSTALLDIR . '/file/',
+              'path' => $_path . '/file/',
+              'supported' => array('image/png',
+                                   'image/jpeg',
+                                   'image/gif',
+                                   'image/svg+xml',
+                                   'audio/mpeg',
+                                   'audio/x-speex',
+                                   'application/ogg',
+                                   'application/pdf',
+                                   'application/vnd.oasis.opendocument.text',
+                                   'application/vnd.oasis.opendocument.text-template',
+                                   'application/vnd.oasis.opendocument.graphics',
+                                   'application/vnd.oasis.opendocument.graphics-template',
+                                   'application/vnd.oasis.opendocument.presentation',
+                                   'application/vnd.oasis.opendocument.presentation-template',
+                                   'application/vnd.oasis.opendocument.spreadsheet',
+                                   'application/vnd.oasis.opendocument.spreadsheet-template',
+                                   'application/vnd.oasis.opendocument.chart',
+                                   'application/vnd.oasis.opendocument.chart-template',
+                                   'application/vnd.oasis.opendocument.image',
+                                   'application/vnd.oasis.opendocument.image-template',
+                                   'application/vnd.oasis.opendocument.formula',
+                                   'application/vnd.oasis.opendocument.formula-template',
+                                   'application/vnd.oasis.opendocument.text-master',
+                                   'application/vnd.oasis.opendocument.text-web',
+                                   'application/x-zip',
+                                   'application/zip',
+                                   'text/plain',
+                                   'video/mpeg',
+                                   'video/mp4',
+                                   'video/quicktime',
+                                   'video/mpeg'),
+        'file_quota' => 5000000,
+        'user_quota' => 50000000,
+        'monthly_quota' => 15000000,
+        'uploads' => true,
+        'filecommand' => '/usr/bin/file',
+        ),
+        'group' =>
+        array('maxaliases' => 3,
+              'desclimit' => null),
+        'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'),
+        'search' =>
+        array('type' => 'fulltext'),
+        'sessions' =>
+        array('handle' => false, // whether to handle sessions ourselves
+              'debug' => false), // debugging output for sessions
+        'design' =>
+        array('backgroundcolor' => null, // null -> 'use theme default'
+              'contentcolor' => null,
+              'sidebarcolor' => null,
+              'textcolor' => null,
+              'linkcolor' => null,
+              'backgroundimage' => null,
+              'disposition' => null),
+        'notice' =>
+        array('contentlimit' => null),
+        'message' =>
+        array('contentlimit' => null),
+        'http' =>
+        array('client' => 'curl'), // XXX: should this be the default?
+        );
diff --git a/lib/deleteaction.php b/lib/deleteaction.php
deleted file mode 100644 (file)
index f702820..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Base class for deleting things
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Personal
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Sarven Capadisli <csarven@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-     exit(1);
-}
-
-class DeleteAction extends Action
-{
-    var $user         = null;
-    var $notice       = null;
-    var $profile      = null;
-    var $user_profile = null;
-
-    function prepare($args)
-    {
-        parent::prepare($args);
-
-        $this->user   = common_current_user();
-        $notice_id    = $this->trimmed('notice');
-        $this->notice = Notice::staticGet($notice_id);
-
-        if (!$this->notice) {
-            common_user_error(_('No such notice.'));
-            exit;
-        }
-
-        $this->profile      = $this->notice->getProfile();
-        $this->user_profile = $this->user->getProfile();
-
-        return true;
-    }
-
-    function handle($args)
-    {
-        parent::handle($args);
-
-        if (!common_logged_in()) {
-            common_user_error(_('Not logged in.'));
-            exit;
-        } else if ($this->notice->profile_id != $this->user_profile->id) {
-            common_user_error(_('Can\'t delete this notice.'));
-            exit;
-        }
-    }
-
-}
index 0c521db08124a29d77259ae3dfb25df5dadb0f49..6a9b76be11b97391f41ac13292ed76f38bdeba2a 100644 (file)
@@ -44,9 +44,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
  */
 class ErrorAction extends Action
 {
+    static $status = array();
+
     var $code    = null;
     var $message = null;
-    var $status  = null;
     var $default = null;
 
     function __construct($message, $code, $output='php://output', $indent=true)
@@ -88,9 +89,10 @@ class ErrorAction extends Action
      *
      * @return page title
      */
+
     function title()
     {
-        return $this->message;
+        return self::$status[$this->code];
     }
 
     function isReadOnly($args)
index 411f795945a7de10737cbb3eab89a0dce2e5af41..3f3a8d3b094b44cde2f94385d60247e49257eef1 100644 (file)
@@ -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;
         }
 
index aa01f6b1d9d268e5855864efe428027cf4aa5916..64be745bebe85daa14998d451df7eb5bddda4701 100644 (file)
@@ -106,14 +106,16 @@ 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' ){
-            // Browsers don't like it when <?xml it output for non-xhtml documents
+        if (preg_match("/.*\/.*xml/", $type)) {
+            // Required for XML documents
             $this->xw->startDocument('1.0', 'UTF-8');
         }
-        $this->xw->writeDTD('html');
+        $this->xw->writeDTD('html',
+                            '-//W3C//DTD XHTML 1.0 Strict//EN',
+                            'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
 
         $language = $this->getLanguage();
 
index d4cd3ff6e5d21caf08c05e00633f1ded4d00d997..6c296f82a7bfb154db87c28686b3a3592236de74 100644 (file)
@@ -178,9 +178,12 @@ class NoticeListItem extends Widget
     function show()
     {
         $this->showStart();
-        $this->showNotice();
-        $this->showNoticeInfo();
-        $this->showNoticeOptions();
+        if (Event::handle('StartShowNoticeItem', array($this))) {
+            $this->showNotice();
+            $this->showNoticeInfo();
+            $this->showNoticeOptions();
+            Event::handle('EndShowNoticeItem', array($this));
+        }
         $this->showEnd();
     }
 
@@ -469,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,
index e69a00f55f2ab61e588a763e882e926d2c962c06..d617a7df7e6216f52d72d0beec8892487256f94b 100644 (file)
@@ -156,7 +156,6 @@ class StatusNetOAuthDataStore extends OAuthDataStore
         return $this->new_access_token($consumer);
     }
 
-
     /**
      * Revoke specified OAuth token
      *
@@ -363,9 +362,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore
                                   false,
                                   null,
                                   $omb_notice->getIdentifierURI());
-        if (is_string($notice)) {
-            throw new Exception($notice);
-        }
+
         common_broadcast_notice($notice, true);
     }
 
diff --git a/lib/right.php b/lib/right.php
new file mode 100644 (file)
index 0000000..4e0096d
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for user rights
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Authorization
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+/**
+ * class for rights
+ *
+ * Mostly for holding the rights constants
+ *
+ * @category Authorization
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class Right
+{
+    const deleteOthersNotice = 'deleteothersnotice';
+}
+
index c6400605ea9bdc1936829b8e2d92e19c3350159c..0993a63bca506149dcecddf892b6d264d4b1cd8e 100644 (file)
@@ -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];
-    }
 }
index 6014a340eb5f9cdce51e5ac7233365b7b7738b5a..708738832baa20e3880e53c06170d10190b30c3b 100644 (file)
@@ -934,35 +934,16 @@ class TwitterapiAction extends Action
 
     function clientError($msg, $code = 400, $format = 'xml')
     {
-
-        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 ($format == 'xml') {
@@ -984,6 +965,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();
index 56753debe0ac5e1bfdc1d4031eeb0a09aeab70fd..44a377220016ea08347426f5b1bdc97241b930db 100644 (file)
@@ -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;
@@ -1164,7 +1165,7 @@ function common_negotiate_type($cprefs, $sprefs)
     }
 
     if ('text/html' === $besttype) {
-        return "text/html; charset=utf-8";
+        return "text/html";
     }
     return $besttype;
 }
index 8191f518112dd3092f2f3f77c0924c714dd04ff3..54faa0bdbefee085216495efbef62a1e825dcf33 100644 (file)
@@ -38,22 +38,16 @@ if (!defined('STATUSNET')) {
  * This plugin will spoot out the correct JavaScript spell to invoke
  * Piwik Analytics on a page.
  *
- * To use this plugin please add the following three lines to your config.php
+ * To use this plugin add the following to your config.php
  *
- *     require_once('plugins/PiwikAnalyticsPlugin.php');
- *     $pa = new PiwikAnalyticsPlugin("example.com/piwik/","id");
+ *  addPlugin('PiwikAnalytics', array('piwikroot' => 'example.com/piwik/',
+ *                                    'piwikId' => 'id'));
  *
- * exchange example.com/piwik/ with the url to your piwik installation and
- * make sure you don't forget the final /
- * exchange id with the ID your statusnet installation has in your Piwik analytics
+ * Replace 'example.com/piwik/' with the URL to your Piwik installation and
+ * make sure you don't forget the final /.
+ * Replace 'id' with the ID your statusnet installation has in your Piwik
+ * analytics setup - for example '8'.
  *
- * @category Plugin
- * @package  StatusNet
- * @author   Tobias Diekershoff <tobias.diekershoff@gmx.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      Event
  */
 
 class PiwikAnalyticsPlugin extends Plugin
index e30c4115676b3740205af9caec39936a7b1c03eb..0f0d0f9f42309b134298220d3fc1d148e3ae2ed7 100644 (file)
@@ -216,8 +216,6 @@ class RealtimePlugin extends Plugin
                                                               'class' => 'user_in')
                               : array('id' => $action->trimmed('action')));
 
-        $action->elementStart('div', array('id' => 'header'));
-
         // XXX hack to deal with JS that tries to get the
         // root url from page output
 
@@ -230,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/jquery.getUrlParam.js b/plugins/Realtime/jquery.getUrlParam.js
deleted file mode 100644 (file)
index e8f73eb..0000000
+++ /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<qString.length; i++){
-                       if (escape(unescape(qString[i].split("=")[0])) == strParamName){
-                               returnVal.push(qString[i].split("=")[1]);
-                       }
-                       
-         }
-         
-         
-         if (returnVal.length==0) return null;
-         else if (returnVal.length==1) return returnVal[0];
-         else return returnVal;
-       }
-});
\ No newline at end of file
index 57fe0a843651ebf1d29b28a492623c297aa82a45..11e466325ebad553a71c4bdb2c8b373c31289c7e 100644 (file)
@@ -14,23 +14,36 @@ RealtimeUpdate = {
         RealtimeUpdate._replyurl = replyurl;
         RealtimeUpdate._favorurl = favorurl;
         RealtimeUpdate._deleteurl = deleteurl;
+
+        $(window).blur(function() {
+          $('#notices_primary .notice').css({
+            'border-top-color':$('#notices_primary .notice:last').css('border-top-color'),
+            'border-top-style':'dotted'
+          });
+
+          $('#notices_primary .notice:first').css({
+            'border-top-color':'#AAAAAA',
+            'border-top-style':'solid'
+          });
+        });
      },
 
      receive: function(data)
      {
-          id = data.id;
-
-          // Don't add it if it already exists
-          //
-          if ($("#notice-"+id).length > 0) {
-               return;
-          }
-
-          var noticeItem = RealtimeUpdate.makeNoticeItem(data);
-          $("#notices_primary .notices").prepend(noticeItem, true);
-          $("#notices_primary .notice:first").css({display:"none"});
-          $("#notices_primary .notice:first").fadeIn(1000);
-          NoticeReply();
+          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();
+          }, 500);
      },
 
      makeNoticeItem: function(data)
@@ -113,35 +126,55 @@ RealtimeUpdate = {
 
      addPopup: function(url, timeline, iconurl)
      {
-         $('#site_nav_local_views .current a').append('<button id="realtime_timeline" title="Real-time pop window">&#8599;</button>');
+         $('#notices_primary').css({'position':'relative'});
+         $('#notices_primary').prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');
+
          $('#realtime_timeline').css({
-             'margin':'2px 0 0 11px',
-             'background':'transparent url('+ iconurl + ') no-repeat 45% 45%',
-             'text-indent':'-9999px',
-             'width':'16px',
-             'height':'16px',
-             'padding':'0',
+             'margin':'0 0 11px 0',
+             'background':'transparent url('+ iconurl + ') no-repeat 0% 30%',
+             'padding':'0 0 0 20px',
              'display':'block',
-             'float':'right',
+             'position':'absolute',
+             'top':'-20px',
+             'right':'0',
              'border':'none',
-             'cursor':'pointer'
+             'cursor':'pointer',
+             'color':$("a").css("color"),
+             'font-weight':'bold',
+             'font-size':'1em'
          });
+
          $('#realtime_timeline').click(function() {
              window.open(url,
                          timeline,
                          'toolbar=no,resizable=yes,scrollbars=yes,status=yes');
+
              return false;
          });
      },
 
      initPopupWindow: function()
      {
-         window.resizeTo(575, 640);
+         window.resizeTo(500, 550);
          $('address').hide();
-         $('#content').css({'width':'92%'});
+         $('#content').css({'width':'93.5%'});
+
+         $('#form_notice').css({
+            'margin':'18px 0 18px 1.795%',
+            'width':'93%',
+            'max-width':'451px'
+         });
+
+         $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});
+
+         $('.notices li:first-child').css({'border-top-color':'transparent'});
+
+         $('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});
+
+         $('#form_notice #notice_data-attach').css({
+            'left':'auto',
+            'right':'0'
+         });
      }
 }
 
index 71ed3bf7227ff2feb5ce4427c183c07be44a03f4..1266a9700b674ca58f76551b5417eee55cac5667 100644 (file)
@@ -101,7 +101,7 @@ function newSub($i)
 
     $to = User::staticGet('nickname', $tunic);
 
-    if (empty($from)) {
+    if (empty($to)) {
         throw new Exception("Can't find user '$tunic'.");
     }
 
index 5705cfd50e300fcf095d5cb55cc281bb957bc707..586bef624ea154d2a53d60c7a71d7313cd18bf83 100755 (executable)
@@ -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);
index 1b1aec3e6eded1030b368ddff41a6c5bddf3bb95..b2efc07c38c644092b4a1549761efb01af99c330 100755 (executable)
@@ -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);
index aeac4a5e3f6c932ac0e26a24b2c5610ed3999de1..483d7135e1592b2e9656d037b12fa130b667f695 100644 (file)
@@ -7,6 +7,7 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
 
 define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
 define('STATUSNET', true);
+define('LACONICA', true);
 
 require_once INSTALLDIR . '/lib/common.php';
 
index 1c3f7cd96f073d64a8eede2527f61af14ef5aaef..45203bf6e3986f73732f35085d74dbabf58a1457 100644 (file)
@@ -7,6 +7,7 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
 
 define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
 define('STATUSNET', true);
+define('LACONICA', true);
 
 require_once INSTALLDIR . '/lib/common.php';
 
@@ -28,69 +29,71 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
                      array('not a link :: no way',
                            'not a link :: no way'),
                      array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link',
-                           'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
+                           'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" title="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
                      array('http://127.0.0.1',
-                           '<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
+                           '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
                      array('127.0.0.1',
-                           '<a href="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
+                           '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
                      array('127.0.0.1:99',
-                           '<a href="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
+                           '<a href="http://127.0.0.1:99/" title="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
                      array('127.0.0.1/Name:test.php',
-                           '<a href="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
+                           '<a href="http://127.0.0.1/Name:test.php" title="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
                      array('127.0.0.1/~test',
-                           '<a href="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
+                           '<a href="http://127.0.0.1/~test" title="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
                      array('127.0.0.1/+test',
-                           '<a href="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'),
+                           '<a href="http://127.0.0.1/+test" title="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'),
                      array('127.0.0.1/$test',
-                           '<a href="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'),
+                           '<a href="http://127.0.0.1/$test" title="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'),
                      array('127.0.0.1/\'test',
-                           '<a href="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
+                           '<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
                      array('127.0.0.1/"test',
-                           '<a href="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
+                           '<a href="http://127.0.0.1/&quot;test" title="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
                      array('127.0.0.1/-test',
-                           '<a href="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
+                           '<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
                      array('127.0.0.1/_test',
-                           '<a href="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'),
+                           '<a href="http://127.0.0.1/_test" title="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'),
                      array('127.0.0.1/!test',
-                           '<a href="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'),
+                           '<a href="http://127.0.0.1/!test" title="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'),
                      array('127.0.0.1/*test',
-                           '<a href="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'),
+                           '<a href="http://127.0.0.1/*test" title="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'),
                      array('127.0.0.1/test%20stuff',
-                           '<a href="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
+                           '<a href="http://127.0.0.1/test%20stuff" title="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
                      array('http://[::1]:99/test.php',
-                           '<a href="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
+                           '<a href="http://[::1]:99/test.php" title="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
                      array('http://::1/test.php',
-                           '<a href="http://::1/test.php" rel="external">http://::1/test.php</a>'),
+                           '<a href="http://::1/test.php" title="http://::1/test.php" rel="external">http://::1/test.php</a>'),
                      array('http://::1',
-                           '<a href="http://::1/" rel="external">http://::1</a>'),
+                           '<a href="http://::1/" title="http://::1/" rel="external">http://::1</a>'),
                      array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php',
-                           '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'),
+                           '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'),
                      array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php',
-                           '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'),
+                           '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" title="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'),
                      array('2001:4978:1b5:0:21d:e0ff:fe66:59ab',
-                           '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'),
+                           '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'),
                      array('http://127.0.0.1',
-                           '<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
+                           '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
                      array('example.com',
-                           '<a href="http://example.com/" rel="external">example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
                      array('example.com',
-                           '<a href="http://example.com/" rel="external">example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
                      array('http://example.com',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
                      array('http://example.com.',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>.'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'),
                      array('/var/lib/example.so',
                            '/var/lib/example.so'),
                      array('example',
                            'example'),
                      array('user@example.com',
-                           '<a href="mailto:user@example.com" rel="external">user@example.com</a>'),
+                           '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="external">user@example.com</a>'),
                      array('user_name+other@example.com',
-                           '<a href="mailto:user_name+other@example.com" rel="external">user_name+other@example.com</a>'),
+                           '<a href="mailto:user_name+other@example.com" title="mailto:user_name+other@example.com" rel="external">user_name+other@example.com</a>'),
                      array('mailto:user@example.com',
-                           '<a href="mailto:user@example.com" rel="external">mailto:user@example.com</a>'),
+                           '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="external">mailto:user@example.com</a>'),
                      array('mailto:user@example.com?subject=test',
-                           '<a href="mailto:user@example.com?subject=test" rel="external">mailto:user@example.com?subject=test</a>'),
+                           '<a href="mailto:user@example.com?subject=test" title="mailto:user@example.com?subject=test" rel="external">mailto:user@example.com?subject=test</a>'),
+                     array('xmpp:user@example.com',
+                           '<a href="xmpp:user@example.com" title="xmpp:user@example.com" rel="external">xmpp:user@example.com</a>'),
                      array('#example',
                            '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example'))) . '" rel="tag">example</a></span>'),
                      array('#example.com',
@@ -98,165 +101,165 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
                      array('#.net',
                            '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('.net'))) . '" rel="tag">.net</a></span>'),
                      array('http://example',
-                           '<a href="http://example/" rel="external">http://example</a>'),
+                           '<a href="http://example/" title="http://example/" rel="external">http://example</a>'),
                      array('http://3xampl3',
-                           '<a href="http://3xampl3/" rel="external">http://3xampl3</a>'),
+                           '<a href="http://3xampl3/" title="http://3xampl3/" rel="external">http://3xampl3</a>'),
                      array('http://example/',
-                           '<a href="http://example/" rel="external">http://example/</a>'),
+                           '<a href="http://example/" title="http://example/" rel="external">http://example/</a>'),
                      array('http://example/path',
-                           '<a href="http://example/path" rel="external">http://example/path</a>'),
+                           '<a href="http://example/path" title="http://example/path" rel="external">http://example/path</a>'),
                      array('http://example.com',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
                      array('https://example.com',
-                           '<a href="https://example.com/" rel="external">https://example.com</a>'),
+                           '<a href="https://example.com/" title="https://example.com/" rel="external">https://example.com</a>'),
                      array('ftp://example.com',
-                           '<a href="ftp://example.com/" rel="external">ftp://example.com</a>'),
+                           '<a href="ftp://example.com/" title="ftp://example.com/" rel="external">ftp://example.com</a>'),
                      array('ftps://example.com',
-                           '<a href="ftps://example.com/" rel="external">ftps://example.com</a>'),
+                           '<a href="ftps://example.com/" title="ftps://example.com/" rel="external">ftps://example.com</a>'),
                      array('http://user@example.com',
-                           '<a href="http://user@example.com/" rel="external">http://user@example.com</a>'),
+                           '<a href="http://user@example.com/" title="http://user@example.com/" rel="external">http://user@example.com</a>'),
                      array('http://user:pass@example.com',
-                           '<a href="http://user:pass@example.com/" rel="external">http://user:pass@example.com</a>'),
+                           '<a href="http://user:pass@example.com/" title="http://user:pass@example.com/" rel="external">http://user:pass@example.com</a>'),
                      array('http://example.com:8080',
-                           '<a href="http://example.com:8080/" rel="external">http://example.com:8080</a>'),
+                           '<a href="http://example.com:8080/" title="http://example.com:8080/" rel="external">http://example.com:8080</a>'),
                      array('http://example.com:8080/test.php',
-                           '<a href="http://example.com:8080/test.php" rel="external">http://example.com:8080/test.php</a>'),
+                           '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="external">http://example.com:8080/test.php</a>'),
                      array('example.com:8080/test.php',
-                           '<a href="http://example.com:8080/test.php" rel="external">example.com:8080/test.php</a>'),
+                           '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="external">example.com:8080/test.php</a>'),
                      array('http://www.example.com',
-                           '<a href="http://www.example.com/" rel="external">http://www.example.com</a>'),
+                           '<a href="http://www.example.com/" title="http://www.example.com/" rel="external">http://www.example.com</a>'),
                      array('http://example.com/',
-                           '<a href="http://example.com/" rel="external">http://example.com/</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com/</a>'),
                      array('http://example.com/path',
-                           '<a href="http://example.com/path" rel="external">http://example.com/path</a>'),
+                           '<a href="http://example.com/path" title="http://example.com/path" rel="external">http://example.com/path</a>'),
                      array('http://example.com/path.html',
-                           '<a href="http://example.com/path.html" rel="external">http://example.com/path.html</a>'),
+                           '<a href="http://example.com/path.html" title="http://example.com/path.html" rel="external">http://example.com/path.html</a>'),
                      array('http://example.com/path.html#fragment',
-                           '<a href="http://example.com/path.html#fragment" rel="external">http://example.com/path.html#fragment</a>'),
+                           '<a href="http://example.com/path.html#fragment" title="http://example.com/path.html#fragment" rel="external">http://example.com/path.html#fragment</a>'),
                      array('http://example.com/path.php?foo=bar&bar=foo',
-                           '<a href="http://example.com/path.php?foo=bar&amp;bar=foo" rel="external">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
+                           '<a href="http://example.com/path.php?foo=bar&amp;bar=foo" title="http://example.com/path.php?foo=bar&amp;bar=foo" rel="external">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
                      array('http://example.com.',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>.'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'),
                      array('http://müllärör.de',
-                           '<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="external">http://müllärör.de</a>'),
+                           '<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" title="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="external">http://müllärör.de</a>'),
                      array('http://ﺱﺲﺷ.com',
-                           '<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="external">http://ﺱﺲﺷ.com</a>'),
+                           '<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" title="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="external">http://ﺱﺲﺷ.com</a>'),
                      array('http://сделаткартинки.com',
-                           '<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="external">http://сделаткартинки.com</a>'),
+                           '<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" title="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="external">http://сделаткартинки.com</a>'),
                      array('http://tūdaliņ.lv',
-                           '<a href="http://t&#x16B;dali&#x146;.lv/" rel="external">http://tūdaliņ.lv</a>'),
+                           '<a href="http://t&#x16B;dali&#x146;.lv/" title="http://t&#x16B;dali&#x146;.lv/" rel="external">http://tūdaliņ.lv</a>'),
                      array('http://brændendekærlighed.com',
-                           '<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="external">http://brændendekærlighed.com</a>'),
+                           '<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" title="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="external">http://brændendekærlighed.com</a>'),
                      array('http://あーるいん.com',
-                           '<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="external">http://あーるいん.com</a>'),
+                           '<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" title="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="external">http://あーるいん.com</a>'),
                      array('http://예비교사.com',
-                           '<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="external">http://예비교사.com</a>'),
+                           '<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" title="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="external">http://예비교사.com</a>'),
                      array('http://example.com.',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>.'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'),
                      array('http://example.com?',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>?'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>?'),
                      array('http://example.com!',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>!'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>!'),
                      array('http://example.com,',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>,'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>,'),
                      array('http://example.com;',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>;'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>;'),
                      array('http://example.com:',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>:'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>:'),
                      array('\'http://example.com\'',
-                           '\'<a href="http://example.com/" rel="external">http://example.com</a>\''),
+                           '\'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>\''),
                      array('"http://example.com"',
-                           '&quot;<a href="http://example.com/" rel="external">http://example.com</a>&quot;'),
+                           '&quot;<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>&quot;'),
                      array('http://example.com',
-                           '<a href="http://example.com/" rel="external">http://example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'),
                      array('(http://example.com)',
-                           '(<a href="http://example.com/" rel="external">http://example.com</a>)'),
+                           '(<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>)'),
                      array('[http://example.com]',
-                           '[<a href="http://example.com/" rel="external">http://example.com</a>]'),
+                           '[<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>]'),
                      array('<http://example.com>',
-                           '&lt;<a href="http://example.com/" rel="external">http://example.com</a>&gt;'),
+                           '&lt;<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>&gt;'),
                      array('http://example.com/path/(foo)/bar',
-                           '<a href="http://example.com/path/(foo)/bar" rel="external">http://example.com/path/(foo)/bar</a>'),
+                           '<a href="http://example.com/path/(foo)/bar" title="http://example.com/path/(foo)/bar" rel="external">http://example.com/path/(foo)/bar</a>'),
                      array('http://example.com/path/[foo]/bar',
-                           '<a href="http://example.com/path/[foo]/bar" rel="external">http://example.com/path/[foo]/bar</a>'),
+                           '<a href="http://example.com/path/[foo]/bar" title="http://example.com/path/[foo]/bar" rel="external">http://example.com/path/[foo]/bar</a>'),
                      array('http://example.com/path/foo/(bar)',
-                           '<a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>'),
+                           '<a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>'),
                      //Not a valid url - urls cannot contain unencoded square brackets
                      array('http://example.com/path/foo/[bar]',
-                           '<a href="http://example.com/path/foo/[bar]" rel="external">http://example.com/path/foo/[bar]</a>'),
+                           '<a href="http://example.com/path/foo/[bar]" title="http://example.com/path/foo/[bar]" rel="external">http://example.com/path/foo/[bar]</a>'),
                      array('Hey, check out my cool site http://example.com okay?',
-                           'Hey, check out my cool site <a href="http://example.com/" rel="external">http://example.com</a> okay?'),
+                           'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a> okay?'),
                      array('What about parens (e.g. http://example.com/path/foo/(bar))?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)?'),
+                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)?'),
                      array('What about parens (e.g. http://example.com/path/foo/(bar)?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>?'),
+                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>?'),
                      array('What about parens (e.g. http://example.com/path/foo/(bar).)?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>.)?'),
+                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>.)?'),
                      //Not a valid url - urls cannot contain unencoded commas
                      array('What about parens (e.g. http://example.com/path/(foo,bar)?',
-                           'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" rel="external">http://example.com/path/(foo,bar)</a>?'),
+                           'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="external">http://example.com/path/(foo,bar)</a>?'),
                      array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" rel="external">http://example.com/path/((((foo)/bar)</a>?'),
+                           'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" title="http://example.com/path/((((foo)/bar)" rel="external">http://example.com/path/((((foo)/bar)</a>?'),
                      array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" rel="external">http://example.com/path/(foo))))/bar</a>)?'),
+                           'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" title="http://example.com/path/(foo))))/bar" rel="external">http://example.com/path/(foo))))/bar</a>)?'),
                      array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" rel="external">http://example.com/path/foo/((((bar)</a>?'),
+                           'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" title="http://example.com/path/foo/((((bar)" rel="external">http://example.com/path/foo/((((bar)</a>?'),
                      array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)))?'),
+                           'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)))?'),
                      array('example.com',
-                           '<a href="http://example.com/" rel="external">example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
                      array('example.org',
-                           '<a href="http://example.org/" rel="external">example.org</a>'),
+                           '<a href="http://example.org/" title="http://example.org/" rel="external">example.org</a>'),
                      array('example.co.uk',
-                           '<a href="http://example.co.uk/" rel="external">example.co.uk</a>'),
+                           '<a href="http://example.co.uk/" title="http://example.co.uk/" rel="external">example.co.uk</a>'),
                      array('www.example.co.uk',
-                           '<a href="http://www.example.co.uk/" rel="external">www.example.co.uk</a>'),
+                           '<a href="http://www.example.co.uk/" title="http://www.example.co.uk/" rel="external">www.example.co.uk</a>'),
                      array('farm1.images.example.co.uk',
-                           '<a href="http://farm1.images.example.co.uk/" rel="external">farm1.images.example.co.uk</a>'),
+                           '<a href="http://farm1.images.example.co.uk/" title="http://farm1.images.example.co.uk/" rel="external">farm1.images.example.co.uk</a>'),
                      array('example.museum',
-                           '<a href="http://example.museum/" rel="external">example.museum</a>'),
+                           '<a href="http://example.museum/" title="http://example.museum/" rel="external">example.museum</a>'),
                      array('example.travel',
-                           '<a href="http://example.travel/" rel="external">example.travel</a>'),
+                           '<a href="http://example.travel/" title="http://example.travel/" rel="external">example.travel</a>'),
                      array('example.com.',
-                           '<a href="http://example.com/" rel="external">example.com</a>.'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.'),
                      array('example.com?',
-                           '<a href="http://example.com/" rel="external">example.com</a>?'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>?'),
                      array('example.com!',
-                           '<a href="http://example.com/" rel="external">example.com</a>!'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>!'),
                      array('example.com,',
-                           '<a href="http://example.com/" rel="external">example.com</a>,'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>,'),
                      array('example.com;',
-                           '<a href="http://example.com/" rel="external">example.com</a>;'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>;'),
                      array('example.com:',
-                           '<a href="http://example.com/" rel="external">example.com</a>:'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>:'),
                      array('\'example.com\'',
-                           '\'<a href="http://example.com/" rel="external">example.com</a>\''),
+                           '\'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>\''),
                      array('"example.com"',
-                           '&quot;<a href="http://example.com/" rel="external">example.com</a>&quot;'),
+                           '&quot;<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>&quot;'),
                      array('example.com',
-                           '<a href="http://example.com/" rel="external">example.com</a>'),
+                           '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'),
                      array('(example.com)',
-                           '(<a href="http://example.com/" rel="external">example.com</a>)'),
+                           '(<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>)'),
                      array('[example.com]',
-                           '[<a href="http://example.com/" rel="external">example.com</a>]'),
+                           '[<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>]'),
                      array('<example.com>',
-                           '&lt;<a href="http://example.com/" rel="external">example.com</a>&gt;'),
+                           '&lt;<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>&gt;'),
                      array('Hey, check out my cool site example.com okay?',
-                           'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a> okay?'),
+                           'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a> okay?'),
                      array('Hey, check out my cool site example.com.I made it.',
-                           'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.I made it.'),
+                           'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.I made it.'),
                      array('Hey, check out my cool site example.com.Funny thing...',
-                           'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.Funny thing...'),
+                           'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.Funny thing...'),
                      array('Hey, check out my cool site example.com.You will love it.',
-                           'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.You will love it.'),
+                           'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.You will love it.'),
                      array('What about parens (e.g. example.com/path/foo/(bar))?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>)?'),
+                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>)?'),
                      array('What about parens (e.g. example.com/path/foo/(bar)?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>?'),
+                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>?'),
                      array('What about parens (e.g. example.com/path/foo/(bar).)?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>.)?'),
+                           'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>.)?'),
                      array('What about parens (e.g. example.com/path/(foo,bar)?',
-                           'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" rel="external">example.com/path/(foo,bar)</a>?'),
+                           'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="external">example.com/path/(foo,bar)</a>?'),
                      array('file.ext',
                            'file.ext'),
                      array('file.html',
diff --git a/tests/UserRightsTest.php b/tests/UserRightsTest.php
new file mode 100644 (file)
index 0000000..6544ee5
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+    print "This script must be run from the command line\n";
+    exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('STATUSNET', true);
+
+require_once INSTALLDIR . '/lib/common.php';
+
+class UserRightsTest extends PHPUnit_Framework_TestCase
+{
+    protected $user = null;
+
+    function setUp()
+    {
+        $this->user = User::register(array('nickname' => 'userrightstestuser'));
+    }
+
+    function tearDown()
+    {
+        $profile = $this->user->getProfile();
+        $this->user->delete();
+        $profile->delete();
+    }
+
+    function testInvalidRole()
+    {
+        $this->assertFalse($this->user->hasRole('invalidrole'));
+    }
+
+    function standardRoles()
+    {
+        return array('admin', 'moderator');
+    }
+
+    /**
+     * @dataProvider standardRoles
+     *
+     */
+
+    function testUngrantedRole($role)
+    {
+        $this->assertFalse($this->user->hasRole($role));
+    }
+
+    /**
+     * @dataProvider standardRoles
+     *
+     */
+
+    function testGrantedRole($role)
+    {
+        $this->user->grantRole($role);
+        $this->assertFalse($this->user->hasRole($role));
+    }
+}
\ No newline at end of file
index 1f37a7637bc8e69ab5fc3ce4a0caad5ab119a0c1..7706fba4845b58ab59daeec51e070eb58d296d7f 100644 (file)
@@ -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 {