]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch '0.8.x' of git@gitorious.org:+laconica-developers/laconica/dev into...
authorRobin Millette <millette@controlyourself.ca>
Sun, 31 May 2009 21:12:04 +0000 (17:12 -0400)
committerRobin Millette <millette@controlyourself.ca>
Sun, 31 May 2009 21:12:04 +0000 (17:12 -0400)
Conflicts:

js/util.js
lib/attachmentlist.php

23 files changed:
README
actions/api.php
actions/conversation.php
actions/designsettings.php
actions/shownotice.php
classes/Foreign_link.php
classes/Memcached_DataObject.php
db/laconica.sql
db/notice_source.sql
js/util.js
lib/attachmentlist.php
lib/common.php
lib/noticelist.php
lib/noticesection.php
plugins/FBConnect/FBConnectAuth.php
plugins/FBConnect/FBConnectPlugin.php
plugins/FBConnect/FBConnectSettings.php
scripts/fixup_utf8.php [new file with mode: 0644]
theme/base/css/display.css
theme/base/css/ie.css
theme/base/images/icons/twotone/green/clip-02.gif [new file with mode: 0644]
theme/default/css/display.css
theme/identica/css/display.css

diff --git a/README b/README
index 9207f3e900ddfa8251d530ac44e8c7e782fc6b7c..76b56a52e5a869cddd54539bef9849a0e1decc02 100644 (file)
--- a/README
+++ b/README
@@ -694,6 +694,13 @@ to users on a remote site. (Or not... it's not well tested.) The
 Upgrading
 =========
 
+IMPORTANT NOTE: Laconica 0.7.4 introduced a fix for some
+incorrectly-stored international characters ("UTF-8"). For new
+installations, it will now store non-ASCII characters correctly.
+However, older installations will have the incorrect storage, and will
+consequently show up "wrong" in browsers. See below for how to deal
+with this situation.
+
 If you've been using Laconica 0.6, 0.5 or lower, or if you've been
 tracking the "git" version of the software, you will probably want
 to upgrade and keep your existing data. There is no automated upgrade
@@ -783,6 +790,29 @@ problem.
 3. When fixup_inboxes is finished, you can set the enabled flag to
    'true'.
 
+UTF-8 Database
+--------------
+
+Laconica 0.7.4 introduced a fix for some incorrectly-stored
+international characters ("UTF-8"). This fix is not
+backwards-compatible; installations from before 0.7.4 will show
+non-ASCII characters of old notices incorrectly. This section explains
+what to do.
+
+0. You can disable the new behaviour by setting the 'db''utf8' config
+   option to "false". You should only do this until you're ready to
+   convert your DB to the new format.
+1. When you're ready to convert, you can run the fixup_utf8.php script
+   in the scripts/ subdirectory. If you've had the "new behaviour"
+   enabled (probably a good idea), you can give the ID of the first
+   "new" notice as a parameter, and only notices before that one will
+   be converted. Notices are converted in reverse chronological order,
+   so the most recent (and visible) ones will be converted first. The
+   script should work whether or not you have the 'db''utf8' config
+   option enabled.
+2. When you're ready, set $config['db']['utf8'] to true, so that
+   new notices will be stored correctly.
+
 Configuration options
 =====================
 
@@ -910,6 +940,10 @@ mirror: you can set this to an array of DSNs, like the above
        and adding the slaves to this array. Note that if you want some
        requests to go to the 'database' (master) server, you'll need
        to include it in this array, too.
+utf8: whether to talk to the database in UTF-8 mode. This is the default
+      with new installations, but older sites may want to turn it off
+      until they get their databases fixed up. See "UTF-8 database"
+      above for details.
 
 syslog
 ------
@@ -1162,6 +1196,21 @@ reporturl: URL to post statistics to. Defaults to Laconica developers'
            set 'run' to 'never' than to set this value to something
            nonsensical.
 
+
+attachments
+-----------
+
+The software lets users upload files with their notices. You can configure
+the types of accepted files by mime types and a trio of quota options:
+per file, per user (total), per user per month.
+
+supported: an array of mime types you accept to store and distribute,
+           like 'image/gif', 'video/mpeg', 'audio/mpeg', etc.
+file_quota: maximum size for a single file upload in bytes.
+user_quota: total size in bytes a user can store.
+monthly_quota: total size permitted in the current month.
+
+
 Troubleshooting
 ===============
 
index 8762b4bcd3efc974831252987f72b8bb33bd4041..b25ba99f30cfcf44b56f6a477856b9c1c82e675c 100644 (file)
@@ -67,6 +67,7 @@ class ApiAction extends Action
                     $this->process_command();
                 } else {
                     # basic authentication failed
+                    common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname.");
                     $this->show_basic_auth_error();
                 }
             }
index ef189016aa358bfca4be1c0934902893ab948466..0d7cb9a8744189935e76c7ff5242698f2f5f4d91 100644 (file)
@@ -179,14 +179,14 @@ class ConversationTree extends NoticeList
 
         $this->out->elementStart('div', array('id' =>'notices_primary'));
         $this->out->element('h2', null, _('Notices'));
-        $this->out->elementStart('ul', array('class' => 'notices'));
+        $this->out->elementStart('ol', array('class' => 'notices xoxo'));
 
         if (array_key_exists('root', $this->tree)) {
             $rootid = $this->tree['root'][0];
             $this->showNoticePlus($rootid);
         }
 
-        $this->out->elementEnd('ul');
+        $this->out->elementEnd('ol');
         $this->out->elementEnd('div');
 
         return $cnt;
@@ -215,13 +215,13 @@ class ConversationTree extends NoticeList
         if (array_key_exists($id, $this->tree)) {
             $children = $this->tree[$id];
 
-            $this->out->elementStart('ul', array('class' => 'notices'));
+            $this->out->elementStart('ol', array('class' => 'notices'));
 
             foreach ($children as $child) {
                 $this->showNoticePlus($child);
             }
 
-            $this->out->elementEnd('ul');
+            $this->out->elementEnd('ol');
         }
 
         $this->out->elementEnd('li');
@@ -295,4 +295,4 @@ class ConversationTreeItem extends NoticeListItem
     {
         return;
     }
-}
\ No newline at end of file
+}
index 315e5a199c2ce06d29eee3b2c213ba8e06dad906..5774b85378d9e14025ef9a1c229083a48c13e200 100644 (file)
@@ -70,7 +70,7 @@ class DesignsettingsAction extends AccountSettingsAction
     function showContent()
     {
         $user = common_current_user();
-        $this->elementStart('form', array('method' => 'POST',
+        $this->elementStart('form', array('method' => 'post',
                                           'id' => 'form_settings_design',
                                           'class' => 'form_settings',
                                           'action' =>
@@ -82,7 +82,7 @@ class DesignsettingsAction extends AccountSettingsAction
         $this->element('legend', null, _('Change background image'));
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
-        $this->element('label', array('for' => 'design_ background-image_file'), 
+        $this->element('label', array('for' => 'design_background-image_file'), 
                                 _('Upload file'));
         $this->element('input', array('name' => 'design_background-image_file',
                                       'type' => 'file',
index 2c469c9deec69c88a546de8b239007614d6a142c..34c8a8e9464c68e21c47a45ca52467b6b8b3b3d5 100644 (file)
@@ -208,10 +208,10 @@ class ShownoticeAction extends Action
 
     function showContent()
     {
-        $this->elementStart('ul', array('class' => 'notices'));
+        $this->elementStart('ol', array('class' => 'notices xoxo'));
         $nli = new NoticeListItem($this->notice, $this);
         $nli->show();
-        $this->elementEnd('ul');
+        $this->elementEnd('ol');
     }
 
     /**
index 6065609512ce76e8461a3952b910e18cb94c50e1..c0b356ecedd10473e13447d7a14157b8388dc63f 100644 (file)
@@ -11,7 +11,7 @@ class Foreign_link extends Memcached_DataObject
 
     public $__table = 'foreign_link';                    // table name
     public $user_id;                         // int(4)  primary_key not_null
-    public $foreign_id;                      // int(4)  primary_key not_null
+    public $foreign_id;                      // bigint(8)  primary_key not_null unsigned
     public $service;                         // int(4)  primary_key not_null
     public $credentials;                     // varchar(255)
     public $noticesync;                      // tinyint(1)   not_null default_1
index 5f71f716b3dd569f84ef557420b03517ecc7c2f9..52ad4100fcec32cc3a823172b269556fdab32a06 100644 (file)
@@ -227,4 +227,22 @@ class Memcached_DataObject extends DB_DataObject
         $c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
         return new ArrayWrapper($cached);
     }
+
+    // We overload so that 'SET NAMES "utf8"' is called for
+    // each connection
+
+    function _connect()
+    {
+        global $_DB_DATAOBJECT;
+        $exists = !empty($this->_database_dsn_md5) &&
+          isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]);
+        $result = parent::_connect();
+        if (!$exists) {
+            $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+            if (common_config('db', 'utf8')) {
+                $DB->query('SET NAMES "utf8"');
+            }
+        }
+        return $result;
+    }
 }
index 0b20bc172c2bdda55940fcdc82e97abad1f47064..a11e31692548449c4cabfd0629b589961ea577d4 100644 (file)
@@ -285,7 +285,7 @@ create table foreign_user (
 
 create table foreign_link (
      user_id int comment 'link to user on this system, if exists' references user (id),
-     foreign_id int comment 'link ' references foreign_user(id),
+     foreign_id bigint unsigned comment 'link to user on foreign service, if exists' references foreign_user(id),
      service int not null comment 'foreign key to service' references foreign_service(id),
      credentials varchar(255) comment 'authc credentials, typically a password',
      noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
index 1508af1ec882d4863bdfb7a211db80e63b2349cd..d5a280b82cedd18f9ba0df4107b7277c18a4394c 100644 (file)
@@ -2,6 +2,7 @@ INSERT INTO notice_source
     (code, name, url, created)
 VALUES
     ('adium', 'Adium', 'http://www.adiumx.com/', now()),
+    ('AgentSolo.com','AgentSolo.com','http://www.agentsolo.com/', now()),
     ('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
     ('bti','bti','http://gregkh.github.com/bti/', now()),
     ('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
@@ -29,6 +30,7 @@ VALUES
     ('pingvine','PingVine','http://pingvine.com/', now()),
     ('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
     ('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
+    ('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
     ('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
     ('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
     ('rygh.no','rygh.no','http://rygh.no/', now()),
index 85ab48b4c0887638a20cdaa75967b5ff2fe11100..acf44a17c78d9f27fb8cadb76b290652b7dbef9c 100644 (file)
@@ -250,6 +250,7 @@ $(document).ready(function(){
        $("#form_notice").each(addAjaxHidden);
     NoticeHover();
     NoticeReply();
+    NoticeAttachments();
 });
 
 
@@ -288,3 +289,53 @@ function NoticeReplySet(nick,id) {
        }
        return true;
 }
+
+function NoticeAttachments() {
+    $.fn.jOverlay.options = {
+        method : 'GET',
+        data : '',
+        url : '',
+        color : '#000',
+        opacity : '0.6',
+        zIndex : 99,
+        center : true,
+        imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
+        bgClickToClose : true,
+        success : function() {
+            $('#jOverlayContent').append('<button>&#215;</button>');
+            $('#jOverlayContent button').click($.closeOverlay);
+        },
+        timeout : 0
+    };
+
+    $('a.attachment').click(function() {
+        $().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
+        return false;
+    });
+    
+    var t;
+    $("body:not(#shownotice) a.thumbnail").hover(
+        function() {
+            var anchor = $(this);
+            $("a.thumbnail").children('img').hide();
+            anchor.closest(".entry-title").addClass('ov');
+
+            if (anchor.children('img').length == 0) {
+                t = setTimeout(function() {
+                    $.get($('address .url')[0].href+'/attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
+                        anchor.append(data);
+                    });
+                }, 500);
+            }
+            else {
+                anchor.children('img').show();
+            }
+        },
+        function() {
+            clearTimeout(t);
+            $("a.thumbnail").children('img').hide();
+            $(this).closest(".entry-title").removeClass('ov');
+        }
+    );
+}
+
index a58a50f6fe9cfa8d109d7559227bcf500d1dc4fc..61749dca578a1cf0688bb2290b26217990b37dd1 100644 (file)
@@ -83,11 +83,10 @@ class AttachmentList extends Widget
         $atts = new File;
         $att = $atts->getAttachments($this->notice->id);
         if (empty($att)) return 0;
-
-        $this->out->elementStart('dl', array('id' =>'attachment'));
+        $this->out->elementStart('dl', array('id' =>'attachments'));
         $this->out->element('dt', null, _('Attachments'));
         $this->out->elementStart('dd');
-        $this->out->elementStart('ul', array('class' => 'attachments'));
+        $this->out->elementStart('ol', array('class' => 'attachments'));
 
         foreach ($att as $n=>$attachment) {
             $item = $this->newListItem($attachment);
@@ -95,7 +94,7 @@ class AttachmentList extends Widget
         }
 
         $this->out->elementEnd('dd');
-        $this->out->elementEnd('ul');
+        $this->out->elementEnd('ol');
         $this->out->elementEnd('dl');
 
         return count($att);
index ede8d6277f2ebab784ccf5c49cf365b37d7f2992..838f52f9d54ab3448b02674a830876c3a5bea7c2 100644 (file)
@@ -208,6 +208,7 @@ $config['db'] =
         'require_prefix' => 'classes/',
         'class_prefix' => '',
         'mirror' => null,
+        'utf8' => true,
         'db_driver' => 'DB', # XXX: JanRain libs only work with DB
         'quote_identifiers' => false,
         'type' => 'mysql' );
index 420272515e1d9d12895eee965d9cbaf88540b517..5513e317e0406fff6b8396444eaf892778b298be 100644 (file)
@@ -86,7 +86,7 @@ class NoticeList extends Widget
     {
         $this->out->elementStart('div', array('id' =>'notices_primary'));
         $this->out->element('h2', null, _('Notices'));
-        $this->out->elementStart('ul', array('class' => 'notices'));
+        $this->out->elementStart('ol', array('class' => 'notices xoxo'));
 
         $cnt = 0;
 
@@ -101,7 +101,7 @@ class NoticeList extends Widget
             $item->show();
         }
 
-        $this->out->elementEnd('ul');
+        $this->out->elementEnd('ol');
         $this->out->elementEnd('div');
 
         return $cnt;
index 37aafdaf6cb2c4753d522d0d94f1dea7edb2d08f..ca14326861b5aaa92ab614bd71fe67eee7d15707 100644 (file)
@@ -52,12 +52,12 @@ class NoticeSection extends Section
     {
         $notices = $this->getNotices();
         $cnt = 0;
-        $this->out->elementStart('ul', 'notices');
+        $this->out->elementStart('ol', 'notices xoxo');
         while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
             $this->showNotice($notices);
         }
 
-        $this->out->elementEnd('ul');
+        $this->out->elementEnd('ol');
         return ($cnt > NOTICES_PER_SECTION);
     }
 
index 233eb83ab3fbcf57c72657a877f47a7245d17a5f..4699ce636c4405f119f7ae514d83fa3be1e3f17b 100644 (file)
@@ -62,7 +62,28 @@ class FBConnectauthAction extends Action
         parent::handle($args);
 
         if (common_is_real_login()) {
-            $this->clientError(_('Already logged in.'));
+
+            // User is already logged in.  Does she already have a linked Facebook acct?
+            $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_CONNECT_SERVICE);
+
+            if ($flink) {
+
+                // User already has a linked Facebook account and shouldn't be here
+                common_debug('There is already a local user (' . $flink->user_id .
+                    ') linked with this Facebook (' . $this->fbuid . ').');
+
+                // We don't want these cookies
+                getFacebook()->clear_cookie_state();
+
+                $this->clientError(_('There is already a local user linked with this Facebook.'));
+
+            } else {
+
+                // User came from the Facebook connect settings tab, and
+                // probably just wants to link/relink their Facebook account
+                $this->connectUser();
+            }
+
         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
 
             $token = $this->trimmed('token');
@@ -78,7 +99,7 @@ class FBConnectauthAction extends Action
                 }
                 $this->createNewUser();
             } else if ($this->arg('connect')) {
-                $this->connectUser();
+                $this->connectNewUser();
             } else {
                 common_debug(print_r($this->args, true), __FILE__);
                 $this->showForm(_('Something weird happened.'),
@@ -259,7 +280,7 @@ class FBConnectauthAction extends Action
                         303);
     }
 
-    function connectUser()
+    function connectNewUser()
     {
         $nickname = $this->trimmed('nickname');
         $password = $this->trimmed('password');
@@ -290,6 +311,23 @@ class FBConnectauthAction extends Action
         $this->goHome($user->nickname);
     }
 
+    function connectUser()
+    {
+        $user = common_current_user();
+
+        $result = $this->flinkUser($user->id, $this->fbuid);
+
+        if (!$result) {
+            $this->serverError(_('Error connecting user to Facebook.'));
+            return;
+        }
+
+        common_debug("Connected Facebook user $this->fbuid to local user $user->id");
+
+        // Return to Facebook connection settings tab
+        common_redirect(common_local_url('FBConnectSettings'), 303);
+    }
+
     function tryLogin()
     {
         common_debug("Trying Facebook Login...");
index ad5e47e4780bd17449d1ff7d10866ea8e55534cb..c85ef432d4f07c4131e1e10300195faca0f3f067 100644 (file)
@@ -143,23 +143,6 @@ class FBConnectPlugin extends Plugin
 
         if ($user) {
 
-            $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
-                _('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
-            $action->menuItem(common_local_url('profilesettings'),
-                _('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
-            if (common_config('xmpp', 'enabled')) {
-                $action->menuItem(common_local_url('imsettings'),
-                    _('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
-            } else {
-             $action->menuItem(common_local_url('smssettings'),
-                 _('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
-            }
-            $action->menuItem(common_local_url('invite'),
-                _('Invite'),
-                sprintf(_('Invite friends and colleagues to join you on %s'),
-                common_config('site', 'name')),
-                false, 'nav_invitecontact');
-
             $flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
             $fbuid = 0;
 
@@ -195,9 +178,25 @@ class FBConnectPlugin extends Plugin
                 }
             }
 
-            // Need to override the Logout link to make it do FB stuff
+            $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
+                _('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
+            $action->menuItem(common_local_url('profilesettings'),
+                _('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
+            if (common_config('xmpp', 'enabled')) {
+                $action->menuItem(common_local_url('imsettings'),
+                    _('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
+            } else {
+             $action->menuItem(common_local_url('smssettings'),
+                 _('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
+            }
+            $action->menuItem(common_local_url('invite'),
+                _('Invite'),
+                sprintf(_('Invite friends and colleagues to join you on %s'),
+                common_config('site', 'name')),
+                false, 'nav_invitecontact');
 
-            if ($fbuid > 0) {
+            // Need to override the Logout link to make it do FB stuff
+            if ($flink && $fbuid > 0) {
 
                 $logout_url = common_local_url('logout');
                 $title =  _('Logout from the site');
@@ -258,21 +257,32 @@ class FBConnectPlugin extends Plugin
         return true;
     }
 
-    function onEndLogout($action)
+    function onStartLogout($action)
     {
-        try {
+        $user = common_current_user();
+
+        $flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
+
+        $action->logout();
+
+        if ($flink) {
 
             $facebook = getFacebook();
-            $fbuid = $facebook->get_loggedin_user();
 
-            if ($fbuid > 0) {
-                $facebook->logout(common_local_url('public'));
-            }
+            try {
+                $fbuid = $facebook->get_loggedin_user();
 
-        } catch (Exception $e) {
-            common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
-                $e->getMessage());
+                if ($fbuid > 0) {
+                    $facebook->logout(common_local_url('public'));
+                }
+
+            } catch (Exception $e) {
+                common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
+                    $e->getMessage());
+            }
         }
+
+        return true;
     }
 
 }
index 7e255f43a68d0f58d70958e003e48214abe3fa4f..034ecebae21b74df88c349435dd14e208d000ee2 100644 (file)
@@ -78,63 +78,73 @@ class FBConnectSettingsAction extends ConnectSettingsAction
     function showContent()
     {
         $user = common_current_user();
-
         $flink = Foreign_link::getByUserID($user->id, FACEBOOK_CONNECT_SERVICE);
 
+        $this->elementStart('form', array('method' => 'post',
+                                          'id' => 'form_settings_facebook',
+                                          'class' => 'form_settings',
+                                          'action' =>
+                                          common_local_url('FBConnectSettings')));
+
         if (!$flink) {
 
-            $this->element('p', 'form_note',
+            $this->element('p', 'instructions',
                 _('There is no Facebook user connected to this account.'));
 
             $this->element('fb:login-button', array('onlogin' => 'goto_login()',
                 'length' => 'long'));
 
-            return;
-        }
+        } else {
 
-        $this->element('p', 'form_note',
-                       _('Connected Facebook user:'));
+            $this->element('p', 'form_note',
+                           _('Connected Facebook user'));
+
+            $this->elementStart('p', array('class' => 'facebook-user-display'));
+            $this->elementStart('fb:profile-pic',
+                array('uid' => $flink->foreign_id,
+                      'size' => 'small',
+                      'linked' => 'true',
+                      'facebook-logo' => 'true'));
+            $this->elementEnd('fb:profile-pic');
+
+            $this->elementStart('fb:name', array('uid' => $flink->foreign_id,
+                                                 'useyou' => 'false'));
+            $this->elementEnd('fb:name');
+            $this->elementEnd('p');
 
-        $this->elementStart('p', array('class' => 'facebook-user-display'));
-        $this->elementStart('fb:profile-pic',
-            array('uid' => $flink->foreign_id,
-                  'size' => 'square',
-                  'linked' => 'true',
-                  'facebook-logo' => 'true'));
-        $this->elementEnd('fb:profile-pic');
+            $this->hidden('token', common_session_token());
 
-        $this->elementStart('fb:name', array('uid' => $flink->foreign_id));
-        $this->elementEnd('fb:name');
-        $this->elementEnd('p');
+            $this->elementStart('fieldset');
 
-        $this->elementStart('form', array('method' => 'post',
-                                          'id' => 'form_settings_facebook',
-                                          'class' => 'form_settings',
-                                          'action' =>
-                                          common_local_url('FBConnectSettings')));
+            $this->element('legend', null, _('Disconnect my account from Facebook'));
 
-        $this->hidden('token', common_session_token());
+            if (!$user->password) {
 
-        $this->elementStart('fieldset');
+                $this->elementStart('p', array('class' => 'form_guide'));
+                $this->text(_('Disconnecting your Faceboook ' .
+                              'would make it impossible to log in! Please '));
+                $this->element('a',
+                    array('href' => common_local_url('passwordsettings')),
+                        _('set a password'));
 
-        $this->element('legend', null, _('Disconnect my account from Facebook'));
+                $this->text(_(' first.'));
+                $this->elementEnd('p');
+            } else {
 
-        if (!$user->password) {
+                $note = 'Keep your %s account but disconnect from Facebook. ' .
+                    'You\'ll use your %s password to log in.';
 
-            $this->elementStart('p', array('class' => 'form_guide'));
-            $this->text(_('Disconnecting your Faceboook ' .
-                          'would make it impossible to log in! Please '));
-            $this->element('a',
-                array('href' => common_local_url('passwordsettings')),
-                    _('set a password'));
+                $site = common_config('site', 'name');
 
-            $this->text(_(' first.'));
-            $this->elementEnd('p');
-        } else {
-            $this->submit('disconnect', _('Disconnect'));
-         }
+                $this->element('p', 'instructions',
+                    sprintf($note, $site, $site));
+
+                $this->submit('disconnect', _('Disconnect'));
+            }
+
+            $this->elementEnd('fieldset');
+        }
 
-        $this->elementEnd('fieldset');
         $this->elementEnd('form');
     }
 
@@ -171,8 +181,7 @@ class FBConnectSettingsAction extends ConnectSettingsAction
 
             try {
 
-                // XXX: not sure what exactly to do here
-
+                // Clear FB Connect cookies out
                 $facebook = getFacebook();
                 $facebook->clear_cookie_state();
 
@@ -182,7 +191,7 @@ class FBConnectSettingsAction extends ConnectSettingsAction
                         $e->getMessage());
             }
 
-            $this->showForm(_('Facebook user disconnected.'), true);
+            $this->showForm(_('You have disconnected from Facebook.'), true);
 
         } else {
             $this->showForm(_('Not sure what you\'re trying to do.'));
diff --git a/scripts/fixup_utf8.php b/scripts/fixup_utf8.php
new file mode 100644 (file)
index 0000000..e5021ff
--- /dev/null
@@ -0,0 +1,141 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2009, Control Yourself, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+# Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+    print "This script must be run from the command line\n";
+    exit(1);
+}
+
+ini_set("max_execution_time", "0");
+ini_set("max_input_time", "0");
+set_time_limit(0);
+mb_internal_encoding('UTF-8');
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+require_once('DB.php');
+
+function fixup_utf8($id) {
+
+    $dbl = doConnect('latin1');
+
+    if (empty($dbl)) {
+        return;
+    }
+
+    $dbu = doConnect('utf8');
+
+    if (empty($dbu)) {
+        return;
+    }
+
+    // Do a separate DB connection
+
+    $sth = $dbu->prepare("UPDATE notice SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
+
+    if (PEAR::isError($sth)) {
+        echo "ERROR: " . $sth->getMessage() . "\n";
+        return;
+    }
+
+    $sql = 'SELECT id, content, rendered FROM notice ' .
+      'WHERE LENGTH(content) != CHAR_LENGTH(content)';
+
+    if (!empty($id)) {
+        $sql .= ' AND id < ' . $id;
+    }
+
+    $sql .= ' ORDER BY id DESC';
+
+    $rn = $dbl->query($sql);
+
+    if (PEAR::isError($rn)) {
+        echo "ERROR: " . $rn->getMessage() . "\n";
+        return;
+    }
+
+    echo "Number of rows: " . $rn->numRows() . "\n";
+
+    $notice = array();
+
+    while (DB_OK == $rn->fetchInto($notice)) {
+
+        $id = ($notice[0])+0;
+        $content = bin2hex($notice[1]);
+        $rendered = bin2hex($notice[2]);
+
+        echo "$id...";
+
+        $result =& $dbu->execute($sth, array($content, $rendered, $id));
+
+        if (PEAR::isError($result)) {
+            echo "ERROR: " . $result->getMessage() . "\n";
+            continue;
+        }
+
+        $cnt = $dbu->affectedRows();
+
+        if ($cnt != 1) {
+            echo "ERROR: 0 rows affected\n";
+            continue;
+        }
+
+        $notice = Notice::staticGet('id', $id);
+        $notice->decache();
+
+        echo "OK\n";
+    }
+}
+
+function doConnect($charset)
+{
+    $db = DB::connect(common_config('db', 'database'),
+                      array('persistent' => false));
+
+    if (PEAR::isError($db)) {
+        echo "ERROR: " . $db->getMessage() . "\n";
+        return NULL;
+    }
+
+    $result = $db->query("SET NAMES $charset");
+
+    if (PEAR::isError($result)) {
+        echo "ERROR: " . $result->getMessage() . "\n";
+        $db->disconnect();
+        return NULL;
+    }
+
+    $result = $db->autoCommit(true);
+
+    if (PEAR::isError($result)) {
+        echo "ERROR: " . $result->getMessage() . "\n";
+        $db->disconnect();
+        return NULL;
+    }
+
+    return $db;
+}
+
+$id = ($argc > 1) ? $argv[1] : null;
+
+fixup_utf8($id);
index 9bc1417b170954bb38273b0bd13bf87fecdff706..7d495c5395fadbb5604b5e365ba577098884e17e 100644 (file)
@@ -855,20 +855,6 @@ display:inline-block;
 text-transform:lowercase;
 }
 
-.notice .attachment {
-position:relative;
-}
-.notice .attachment img {
-position:absolute;
-top:18px;
-left:0;
-z-index:99;
-}
-#shownotice .notice .attachment img {
-position:static;
-}
-
-
 .notice-options {
 position:relative;
 font-size:0.95em;
@@ -936,6 +922,75 @@ padding:0;
 }
 
 
+.notice .attachment {
+position:relative;
+padding-left:16px;
+}
+#attachments .attachment {
+padding-left:0;
+}
+.notice .attachment img {
+position:absolute;
+top:18px;
+left:0;
+z-index:99;
+}
+#shownotice .notice .attachment img {
+position:static;
+}
+
+#attachments {
+clear:both;
+float:left;
+width:100%;
+margin-top:18px;
+}
+#attachments dt {
+font-weight:bold;
+font-size:1.3em;
+margin-bottom:4px;
+}
+
+#attachments ol li {
+margin-bottom:18px;
+list-style-type:decimal;
+float:left;
+clear:both;
+}
+
+#jOverlayContent,
+#jOverlayContent #content,
+#jOverlayContent #content_inner {
+width: auto !important;
+margin-bottom:0;
+}
+#jOverlayContent #content {
+padding:11px;
+min-height:auto;
+}
+#jOverlayContent .external span {
+display:block;
+margin-bottom:11px;
+}
+#jOverlayContent button {
+position:absolute;
+top:0;
+right:0;
+width:29px;
+height:29px;
+text-align:center;
+font-weight:bold;
+padding:0;
+}
+#jOverlayContent h1 {
+max-width:475px;
+}
+#jOverlayContent #content {
+border-radius:7px;
+-moz-border-radius:7px;
+-webkit-border-radius:7px;
+}
+
 #usergroups #new_group {
 float: left;
 margin-right: 2em;
@@ -1182,6 +1237,7 @@ width:33%;
 }
 #settings_design_color .form_data label {
 float:none;
+display:block;
 }
 #settings_design_color .form_data .swatch {
 padding:11px;
index 5d8bea8ae3f5c1992228021f287448212c0ad2b5..df0388a5ad55e0b0f2d620039d2bab3afa145893 100644 (file)
@@ -30,3 +30,9 @@ margin-right:4px;
 .entity_profile {
 width:64%;
 }
+#jOverlayContent .notice * {
+z-index:1;
+}
+#jOverlayContent .notice .attachment img  {
+z-index:9999;
+}
diff --git a/theme/base/images/icons/twotone/green/clip-02.gif b/theme/base/images/icons/twotone/green/clip-02.gif
new file mode 100644 (file)
index 0000000..77a7297
Binary files /dev/null and b/theme/base/images/icons/twotone/green/clip-02.gif differ
index 737db7ce9691125103befaac6311e8da62d0cff3..e08a4783bd6ba8882fe5246aa50db084c80c6796 100644 (file)
@@ -175,6 +175,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
 }
 
 /* NOTICES */
+.notice .attachment {
+background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
+}
+#attachments .attachment {
+background:none;
+}
 .notice-options .notice_reply a,
 .notice-options form input.submit {
 background-color:transparent;
index f7abac482364621572b2da6c541834b6c90c9ea9..1f1298737cd19430cc3393db22e8accfde5be3a6 100644 (file)
@@ -175,6 +175,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
 }
 
 /* NOTICES */
+.notice .attachment {
+background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
+}
+#attachments .attachment {
+background:none;
+}
 .notice-options .notice_reply a,
 .notice-options form input.submit {
 background-color:transparent;