]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge commit 'refs/merge-requests/51' of https://gitorious.org/social/mainline into...
authorMikael Nordfeldth <mmn@hethane.se>
Wed, 25 Feb 2015 11:52:35 +0000 (12:52 +0100)
committerMikael Nordfeldth <mmn@hethane.se>
Wed, 25 Feb 2015 11:52:35 +0000 (12:52 +0100)
99 files changed:
INSTALL
README.md
actions/apifriendshipscreate.php
actions/apifriendshipsdestroy.php
actions/apifriendshipsexists.php
actions/apifriendshipsshow.php
actions/apitimelineretweetedtome.php
actions/apitimelineuser.php
actions/emailsettings.php
classes/Attention.php
classes/Avatar.php
classes/Config.php
classes/Confirm_address.php
classes/Consumer.php
classes/Conversation.php
classes/Deleted_notice.php
classes/File.php
classes/File_redirection.php
classes/File_thumbnail.php
classes/Foreign_link.php
classes/Foreign_service.php
classes/Foreign_user.php
classes/Group_member.php
classes/Invitation.php
classes/Location_namespace.php
classes/Managed_DataObject.php
classes/Memcached_DataObject.php
classes/Nonce.php
classes/Notice.php
classes/Notice_source.php
classes/Oauth_application.php
classes/Oauth_application_user.php
classes/Oauth_token_association.php
classes/Profile.php
classes/Profile_list.php
classes/Profile_prefs.php
classes/Sms_carrier.php
classes/Status_network.php
classes/Subscription.php
classes/Token.php
classes/User.php
classes/User_group.php
classes/User_im_prefs.php
classes/User_username.php
db/site.sql
install.php
js/util.js
lib/activityimporter.php
lib/apiaction.php
lib/default.php
lib/event.php
lib/imagefile.php
lib/installer.php
lib/mediafile.php
lib/mysqlschema.php
lib/schemaupdater.php
lib/util.php
lib/xmloutputter.php
plugins/Autocomplete/js/autocomplete.go.js
plugins/Blacklist/classes/Homepage_blacklist.php
plugins/Blacklist/classes/Nickname_blacklist.php
plugins/Blog/classes/Blog_entry.php
plugins/Bookmark/classes/Bookmark.php
plugins/DirectMessage/classes/Message.php
plugins/Directory/actions/groupdirectory.php
plugins/Directory/actions/userdirectory.php
plugins/EmailReminder/classes/Email_reminder.php
plugins/Event/classes/Happening.php
plugins/Event/classes/RSVP.php
plugins/FacebookBridge/classes/Notice_to_item.php
plugins/Favorite/classes/Fave.php
plugins/GNUsocialPhoto/classes/Photo.php
plugins/GNUsocialPhotos/classes/gnusocialphoto.php
plugins/GNUsocialPhotos/classes/gnusocialphotoalbum.php
plugins/GNUsocialProfileExtensions/classes/GNUsocialProfileExtensionField.php
plugins/GNUsocialVideo/classes/Video.php
plugins/GroupPrivateMessage/classes/Group_message.php
plugins/NoticeTitle/classes/Notice_title.php
plugins/OStatus/classes/FeedSub.php
plugins/OStatus/classes/HubSub.php
plugins/OStatus/classes/Ostatus_profile.php
plugins/OStatus/classes/Ostatus_source.php
plugins/OStatus/lib/salmonaction.php
plugins/Oembed/classes/File_oembed.php
plugins/OpenID/OpenIDPlugin.php
plugins/OpenID/classes/User_openid.php
plugins/OpenID/classes/User_openid_trustroot.php
plugins/Poll/classes/Poll.php
plugins/Poll/classes/Poll_response.php
plugins/QnA/classes/QnA_Answer.php
plugins/QnA/classes/QnA_Question.php
plugins/RSSCloud/RSSCloudPlugin.php
plugins/Realtime/classes/Realtime_channel.php
plugins/TwitterBridge/classes/Twitter_synch_status.php
plugins/VideoThumbnails/VideoThumbnailsPlugin.php
scripts/clean_file_table.php [new file with mode: 0755]
scripts/clean_profiles.php [new file with mode: 0755]
scripts/upgrade.php
theme/base/css/display.css

diff --git a/INSTALL b/INSTALL
index 0483320a78bc08795afbde082346043a583d37a9..fff63681becfecd7f64530dc2e709d876f4f373f 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -41,6 +41,7 @@ functional setup of GNU Social:
 - php5-curl     Fetching files by HTTP.
 - php5-gd       Image manipulation (scaling).
 - php5-gmp      For Salmon signatures (part of OStatus).
+- php5-intl     Internationalization support (transliteration et al).
 - php5-json     For WebFinger lookups and more.
 - php5-mysqlnd  The native driver for PHP5 MariaDB connections. If you
                   use MySQL, 'mysql' or 'mysqli' may work.
index 3d0e101d69f326d5c8d878ece6b92c9a89b90887..0ef8c6c6032765cb78062ff9b29bc88830c6bbe2 100644 (file)
--- a/README.md
+++ b/README.md
@@ -109,6 +109,7 @@ So far it includes the following changes:
 - Many improvements to ease adoption of the Qvitter front-end <https://github.com/hannesmannerheim/qvitter>
 - Protocol adaptions for improved performance and stability
 - Backing up a user's account now appears to work as it should
+- Emojis 😸
 
 Upgrades from _StatusNet_ 1.1.1 will also experience these improvements:
 
index 873883c6513bd4ea8bac56c2dd2ebe79cedd5edb..e7caf9686914b7720eeec02dca120ba5856b5119 100644 (file)
@@ -29,9 +29,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * Allows the authenticating users to follow (subscribe) the user specified in
@@ -90,7 +88,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
             $this->clientError(_('Could not follow user: profile not found.'), 403);
         }
 
-        if ($this->user->isSubscribed($this->other)) {
+        if ($this->scoped->isSubscribed($this->other)) {
             $errmsg = sprintf(
                 // TRANS: Client error displayed when trying to follow a user that's already being followed.
                 // TRANS: %s is the nickname of the user that is already being followed.
@@ -101,7 +99,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
         }
 
         try {
-            Subscription::start($this->user->getProfile(), $this->other);
+            Subscription::start($this->scoped, $this->other);
         } catch (Exception $e) {
             $this->clientError($e->getMessage(), 403);
         }
index 5f7c85e0aff62bd725a48f634e81e67237fca7b2..5c8036bc458b6db45e8f914259c38f9e3989bb99 100644 (file)
@@ -29,9 +29,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * Allows the authenticating users to unfollow (unsubscribe) the user specified in
@@ -48,7 +46,9 @@ if (!defined('STATUSNET')) {
  */
 class ApiFriendshipsDestroyAction extends ApiAuthAction
 {
-    var $other  = null;
+    protected $needPost = true;
+
+    protected $other = null;
 
     /**
      * Take arguments for running
@@ -58,12 +58,11 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
      * @return boolean success flag
      *
      */
-    function prepare($args)
+    protected function prepare(array $args=array())
     {
         parent::prepare($args);
 
-        $this->user   = $this->auth_user;
-        $this->other  = $this->getTargetProfile($this->arg('id'));
+        $this->other = $this->getTargetProfile($this->arg('id'));
 
         return true;
     }
@@ -73,58 +72,40 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
      *
      * Check the format and show the user info
      *
-     * @param array $args $_REQUEST data (unused)
-     *
      * @return void
      */
-    function handle($args)
+    protected function handle()
     {
-        parent::handle($args);
-
-        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
-            $this->clientError(
-                // TRANS: Client error. POST is a HTTP command. It should not be translated.
-                _('This method requires a POST.'),
-                400,
-                $this->format
-            );
-            return;
-        }
+        parent::handle();
 
         if (!in_array($this->format, array('xml', 'json'))) {
             $this->clientError(
                 // TRANS: Client error displayed when coming across a non-supported API method.
                 _('API method not found.'),
-                404,
-                $this->format
+                404
             );
-            return;
         }
 
-        if (empty($this->other)) {
+        if (!$this->other instanceof Profile) {
             $this->clientError(
                 // TRANS: Client error displayed when trying to unfollow a user that cannot be found.
                 _('Could not unfollow user: User not found.'),
-                403,
-                $this->format
+                403
             );
-            return;
         }
 
         // Don't allow unsubscribing from yourself!
 
-        if ($this->user->id == $this->other->id) {
+        if ($this->scoped->id == $this->other->id) {
             $this->clientError(
                 // TRANS: Client error displayed when trying to unfollow self.
                 _("You cannot unfollow yourself."),
-                403,
-                $this->format
+                403
             );
-            return;
         }
 
         // throws an exception on error
-        Subscription::cancel($this->user->getProfile(), $this->other);
+        Subscription::cancel($this->scoped, $this->other);
 
         $this->initDocument($this->format);
         $this->showProfile($this->other, $this->format);
index 1f76e00b1a7ab7c2a641f372b8ea9486c55e8fb3..4bb771292d61ab964fab7fef40954bf494ad7323 100644 (file)
@@ -29,9 +29,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * Tests for the existence of friendship between two users. Will return true if
@@ -57,7 +55,7 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
      *
      * @return boolean success flag
      */
-    function prepare($args)
+    protected function prepare(array $args=array())
     {
         parent::prepare($args);
 
@@ -72,22 +70,18 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
      *
      * Check the format and show the user info
      *
-     * @param array $args $_REQUEST data (unused)
-     *
      * @return void
      */
-    function handle($args)
+    protected function handle()
     {
-        parent::handle($args);
+        parent::handle();
 
         if (empty($this->profile_a) || empty($this->profile_b)) {
             $this->clientError(
                 // TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
                 _('Two valid IDs or nick names must be supplied.'),
-                400,
-                $this->format
+                400
             );
-            return;
         }
 
         $result = Subscription::exists($this->profile_a, $this->profile_b);
index 5810e148747452ba808ccc4319429b56fd0b3ca7..c08e984b9ad3d2bb288efc36494e9b59566bafb5 100644 (file)
@@ -29,9 +29,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * Outputs detailed information about the relationship between two users
@@ -56,7 +54,7 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
      *
      * @return boolean success flag
      */
-    function prepare($args)
+    protected function prepare(array $args=array())
     {
         parent::prepare($args);
 
@@ -109,13 +107,11 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
      *
      * Check the format and show the user info
      *
-     * @param array $args $_REQUEST data (unused)
-     *
      * @return void
      */
-    function handle($args)
+    protected function handle()
     {
-        parent::handle($args);
+        parent::handle();
 
         if (!in_array($this->format, array('xml', 'json'))) {
             // TRANS: Client error displayed when coming across a non-supported API method.
index 85f52f7388f88c27314534c8c1736b6a4587b74d..92d4b358fe4168dbaf6b452c4de6b5547e16ebbe 100644 (file)
@@ -27,9 +27,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * Show most recent notices that are repeats in user's inbox
@@ -59,7 +57,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
      *
      * @return boolean success flag
      */
-    function prepare($args)
+    protected function prepare(array $args=array())
     {
         parent::prepare($args);
 
@@ -79,35 +77,33 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
      *
      * show a timeline of the user's repeated notices
      *
-     * @param array $args $_REQUEST data (unused)
-     *
      * @return void
      */
-    function handle($args)
+    protected function handle()
     {
-        parent::handle($args);
+        parent::handle();
 
         $offset = ($this->page-1) * $this->cnt;
         $limit  = $this->cnt;
 
         // TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
-        $title      = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
+        $title      = sprintf(_("Repeated to %s"), $this->scoped->getNickname());
         $subtitle   = sprintf(
             // @todo FIXME: $profile is not defined.
             // TRANS: Subtitle for API action that shows most recent notices that are repeats in user's inbox.
             // TRANS: %1$s is the sitename, %2$s is a user nickname, %3$s is a user profile name.
             _('%1$s notices that were to repeated to %2$s / %3$s.'),
-            $sitename, $this->user->nickname, $profile->getBestName()
+            $sitename, $this->scoped->getNickname(), $profile->getBestName()
         );
         $taguribase = TagURI::base();
-        $id         = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
+        $id         = "tag:$taguribase:RepeatedToMe:" . $this->scoped->id;
 
         $link = common_local_url(
             'all',
-             array('nickname' => $this->auth_user->nickname)
+             array('nickname' => $this->scoped->getNickname())
         );
 
-        $strm = $this->auth_user->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
+        $strm = $this->scoped->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
 
         switch ($this->format) {
         case 'xml':
@@ -119,7 +115,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
         case 'atom':
             header('Content-Type: application/atom+xml; charset=utf-8');
 
-            $atom = new AtomNoticeFeed($this->auth_user);
+            $atom = new AtomNoticeFeed($this->scoped->getUser());
 
             $atom->setId($id);
             $atom->setTitle($title);
@@ -137,7 +133,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
             break;
         case 'as':
             header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
-            $doc = new ActivityStreamJSONDocument($this->auth_user);
+            $doc = new ActivityStreamJSONDocument($this->scoped->getUser());
             $doc->setTitle($title);
             $doc->addLink($link, 'alternate', 'text/html');
             $doc->addItemsFromNotices($strm);
index 26c960fa0429b9e1d176713cd4e65e60be43ddfa..abc7fd6a96a13d63c3fd2881dbda0103bbb7885f 100644 (file)
@@ -405,7 +405,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
 
         // Get (safe!) HTML and text versions of the content
 
-        $rendered = $this->purify($sourceContent);
+        $rendered = common_purify($sourceContent);
         $content = common_strip_html($rendered);
 
         $shortened = $this->auth_user->shortenLinks($content);
@@ -504,13 +504,4 @@ class ApiTimelineUserAction extends ApiBareAuthAction
 
         return $saved;
     }
-
-    function purify($content)
-    {
-        require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
-        $config = array('safe' => 1,
-                        'deny_attribute' => 'id,style,on*');
-        return htmLawed($content, $config);
-    }
 }
index 0c2033d821d0587a0bcbf5aeb974d17ad3024ebd..47c6fe54e513a738cedf12a7275d6e8edcbbf19a 100644 (file)
@@ -313,7 +313,7 @@ class EmailsettingsAction extends SettingsAction
      */
     function savePreferences()
     {
-        $user = common_current_user();
+        $user = $this->scoped->getUser();
 
         if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
             $emailnotifysub   = $this->boolean('emailnotifysub');
@@ -323,8 +323,6 @@ class EmailsettingsAction extends SettingsAction
             $emailmicroid     = $this->boolean('emailmicroid');
             $emailpost        = $this->boolean('emailpost');
 
-            assert(!is_null($user)); // should already be checked
-
             $user->query('BEGIN');
 
             $original = clone($user);
@@ -340,6 +338,7 @@ class EmailsettingsAction extends SettingsAction
 
             if ($result === false) {
                 common_log_db_error($user, 'UPDATE', __FILE__);
+                $user->query('ROLLBACK');
                 // TRANS: Server error thrown on database error updating e-mail preferences.
                 $this->serverError(_('Could not update user.'));
             }
index ef0dcb1df7dd4dc56798f087bafdcb48374506da..c15a118e122f7a6f397b2323a8684c4094f20f14 100644 (file)
@@ -22,7 +22,7 @@ class Attention extends Managed_DataObject
     public $__table = 'attention';  // table name
     public $notice_id;              // int(4) primary_key not_null
     public $profile_id;             // int(4) primary_key not_null
-    public $reason;                 // varchar(255)
+    public $reason;                 // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                // datetime()   not_null
     public $modified;               // timestamp   not_null default_CURRENT_TIMESTAMP
 
@@ -33,7 +33,7 @@ class Attention extends Managed_DataObject
             'fields' => array(
                 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice_id to give attention'),
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile_id for feed receiver'),
-                'reason' => array('type' => 'varchar', 'length' => 255, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
+                'reason' => array('type' => 'varchar', 'length' => 191, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index 55abc81b33b3850891b6c3ca6ca80ceddd3efdfd..3b3317b3ef5ed9f58e066a6e95f43aac9392f696 100644 (file)
@@ -15,8 +15,8 @@ class Avatar extends Managed_DataObject
     public $width;                           // int(4)  primary_key not_null
     public $height;                          // int(4)  primary_key not_null
     public $mediatype;                       // varchar(32)   not_null
-    public $filename;                        // varchar(255)
-    public $url;                             // varchar(255)  unique_key
+    public $filename;                        // varchar(191)   not 255 because utf8mb4 takes more space
+    public $url;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -32,8 +32,8 @@ class Avatar extends Managed_DataObject
                 'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
                 'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
                 'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
-                'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'local filename, if local'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'avatar location'),
+                'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'local filename, if local'),
+                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'avatar location'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index 899396d710e13823270698903eaf5dcdfc422ea5..2e8492849c4b9f68abb1586aad52f9406e9c81f2 100644 (file)
@@ -35,7 +35,7 @@ class Config extends Managed_DataObject
     public $__table = 'config';                          // table name
     public $section;                         // varchar(32)  primary_key not_null
     public $setting;                         // varchar(32)  primary_key not_null
-    public $value;                           // varchar(255)
+    public $value;                           // varchar(191)   not 255 because utf8mb4 takes more space
 
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
@@ -46,7 +46,7 @@ class Config extends Managed_DataObject
             'fields' => array(
                 'section' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'default' => '', 'description' => 'configuration section'),
                 'setting' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'default' => '', 'description' => 'configuration setting'),
-                'value' => array('type' => 'varchar', 'length' => 255, 'description' => 'configuration value'),
+                'value' => array('type' => 'varchar', 'length' => 191, 'description' => 'configuration value'),
             ),
             'primary key' => array('section', 'setting'),
         );
index 0ed7796ad40b8458de85c6538d166ad4ee38b13d..91a84feb77218f324ac39eaa8535ad1a0f58a5f0 100644 (file)
@@ -12,8 +12,8 @@ class Confirm_address extends Managed_DataObject
     public $__table = 'confirm_address';                 // table name
     public $code;                            // varchar(32)  primary_key not_null
     public $user_id;                         // int(4)   not_null
-    public $address;                         // varchar(255)   not_null
-    public $address_extra;                   // varchar(255)   not_null
+    public $address;                         // varchar(191)   not_null   not 255 because utf8mb4 takes more space
+    public $address_extra;                   // varchar(191)   not_null   not 255 because utf8mb4 takes more space
     public $address_type;                    // varchar(8)   not_null
     public $claimed;                         // datetime()  
     public $sent;                            // datetime()  
@@ -28,8 +28,8 @@ class Confirm_address extends Managed_DataObject
             'fields' => array(
                 'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'good random code'),
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who requested confirmation'),
-                'address' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'address (email, xmpp, SMS, etc.)'),
-                'address_extra' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'carrier ID, for SMS'),
+                'address' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'address (email, xmpp, SMS, etc.)'),
+                'address_extra' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'carrier ID, for SMS'),
                 'address_type' => array('type' => 'varchar', 'length' => 8, 'not null' => true, 'description' => 'address type ("email", "xmpp", "sms")'),
                 'claimed' => array('type' => 'datetime', 'description' => 'date this was claimed for queueing'),
                 'sent' => array('type' => 'datetime', 'description' => 'date this was sent for queueing'),
index 68e973bfb095bcfe55180c539026856b04c1f087..4121938ed864fd090ab25164980267492a8d737c 100644 (file)
@@ -10,8 +10,8 @@ class Consumer extends Managed_DataObject
     /* the code below is auto generated do not remove the above tag */
 
     public $__table = 'consumer';                        // table name
-    public $consumer_key;                    // varchar(255)  primary_key not_null
-    public $consumer_secret;                 // varchar(255)   not_null
+    public $consumer_key;                    // varchar(191)  primary_key not_null   not 255 because utf8mb4 takes more space
+    public $consumer_secret;                 // varchar(191)   not_null   not 255 because utf8mb4 takes more space
     public $seed;                            // char(32)   not_null
     public $created;                         // datetime   not_null
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
@@ -24,8 +24,8 @@ class Consumer extends Managed_DataObject
         return array(
             'description' => 'OAuth consumer record',
             'fields' => array(
-                'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
-                'consumer_secret' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'secret value'),
+                'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
+                'consumer_secret' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'secret value'),
                 'seed' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'seed for new tokens by this consumer'),
 
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
index 56f61c63ab2c1453ebd8250c6c17b721bd358bcc..343668cc49d95e6632488c77f87668ed690aaecf 100644 (file)
@@ -35,7 +35,7 @@ class Conversation extends Managed_DataObject
 {
     public $__table = 'conversation';        // table name
     public $id;                              // int(4)  primary_key not_null
-    public $uri;                             // varchar(255)  unique_key
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $created;                         // datetime   not_null
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
 
@@ -44,7 +44,7 @@ class Conversation extends Managed_DataObject
         return array(
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'should be set from root notice id (since 2014-03-01 commit)'),
-                'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 255, 'description' => 'URI of the conversation'),
+                'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 191, 'description' => 'URI of the conversation'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index 4c17be185a0ff438fe34004dc0fb28d0c7d9f9cd..a9167f19a48ee2c5069123567562dfcc13d1e70f 100644 (file)
@@ -34,7 +34,7 @@ class Deleted_notice extends Managed_DataObject
     public $__table = 'deleted_notice';                  // table name
     public $id;                              // int(4)  primary_key not_null
     public $profile_id;                      // int(4)   not_null
-    public $uri;                             // varchar(255)  unique_key
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $deleted;                         // datetime()   not_null
 
@@ -47,7 +47,7 @@ class Deleted_notice extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'identity of notice'),
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'author of the notice'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
                 'deleted' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
             ),
index ce2f9401618286bcfd9485f8f3682add5c8df0f2..242d109804ffb0190fbd19c2abba5fa1bd71f944 100644 (file)
@@ -26,29 +26,36 @@ class File extends Managed_DataObject
 {
     public $__table = 'file';                            // table name
     public $id;                              // int(4)  primary_key not_null
-    public $url;                             // varchar(255)  unique_key
+    public $urlhash;                         // varchar(64)  unique_key
+    public $url;                             // text
+    public $filehash;                        // varchar(64)     indexed
     public $mimetype;                        // varchar(50)
     public $size;                            // int(4)
-    public $title;                           // varchar(255)
+    public $title;                           // varchar(191)   not 255 because utf8mb4 takes more space
     public $date;                            // int(4)
     public $protected;                       // int(4)
-    public $filename;                        // varchar(255)
+    public $filename;                        // varchar(191)   not 255 because utf8mb4 takes more space
     public $width;                           // int(4)
     public $height;                          // int(4)
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
+    const URLHASH_ALG = 'sha256';
+    const FILEHASH_ALG = 'sha256';
+
     public static function schemaDef()
     {
         return array(
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'destination URL after following redirections'),
+                'urlhash' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'sha256 of destination URL (url field)'),
+                'url' => array('type' => 'text', 'description' => 'destination URL after following possible redirections'),
+                'filehash' => array('type' => 'varchar', 'length' => 64, 'not null' => false, 'description' => 'sha256 of the file contents, only for locally stored files of course'),
                 'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
                 'size' => array('type' => 'int', 'description' => 'size of resource when available'),
-                'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of resource when available'),
+                'title' => array('type' => 'varchar', 'length' => 191, 'description' => 'title of resource when available'),
                 'date' => array('type' => 'int', 'description' => 'date of resource according to http query'),
                 'protected' => array('type' => 'int', 'description' => 'true when URL is private (needs login)'),
-                'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if a local file, name of the file'),
+                'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'if a local file, name of the file'),
                 'width' => array('type' => 'int', 'description' => 'width in pixels, if it can be described as such and data is available'),
                 'height' => array('type' => 'int', 'description' => 'height in pixels, if it can be described as such and data is available'),
 
@@ -56,7 +63,10 @@ class File extends Managed_DataObject
             ),
             'primary key' => array('id'),
             'unique keys' => array(
-                'file_url_key' => array('url'),
+                'file_urlhash_key' => array('urlhash'),
+            ),
+            'indexes' => array(
+                'file_filehash_idx' => array('filehash'),
             ),
         );
     }
@@ -77,10 +87,11 @@ class File extends Managed_DataObject
         // I don't know why we have to keep doing this but I'm adding this last check to avoid
         // uniqueness bugs.
 
-        $file = File::getKV('url', $given_url);
+        $file = File::getKV('urlhash', self::hashurl($given_url));
         
         if (!$file instanceof File) {
             $file = new File;
+            $file->urlhash = self::hashurl($given_url);
             $file->url = $given_url;
             if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected'];
             if (!empty($redir_data['title'])) $file->title = $redir_data['title'];
@@ -122,51 +133,56 @@ class File extends Managed_DataObject
             throw new ServerException('No canonical URL from given URL to process');
         }
 
-        $file = File::getKV('url', $given_url);
-        if (!$file instanceof File) {
+        $file = null;
+
+        try {
+            $file = File::getByUrl($given_url);
+        } catch (NoResultException $e) {
             // First check if we have a lookup trace for this URL already
-            $file_redir = File_redirection::getKV('url', $given_url);
-            if ($file_redir instanceof File_redirection) {
+            try {
+                $file_redir = File_redirection::getByUrl($given_url);
                 $file = File::getKV('id', $file_redir->file_id);
                 if (!$file instanceof File) {
                     // File did not exist, let's clean up the File_redirection entry
                     $file_redir->delete();
                 }
+            } catch (NoResultException $e) {
+                // We just wanted to doublecheck whether a File_thumbnail we might've had
+                // actually referenced an existing File object.
             }
+        }
 
-            // If we still don't have a File object, let's create one now!
-            if (!$file instanceof File) {
-                // @fixme for new URLs this also looks up non-redirect data
-                // such as target content type, size, etc, which we need
-                // for File::saveNew(); so we call it even if not following
-                // new redirects.
-                $redir_data = File_redirection::where($given_url);
-                if (is_array($redir_data)) {
-                    $redir_url = $redir_data['url'];
-                } elseif (is_string($redir_data)) {
-                    $redir_url = $redir_data;
-                    $redir_data = array();
-                } else {
-                    // TRANS: Server exception thrown when a URL cannot be processed.
-                    throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
-                }
+        // If we still don't have a File object, let's create one now!
+        if (!$file instanceof File) {
+            // @fixme for new URLs this also looks up non-redirect data
+            // such as target content type, size, etc, which we need
+            // for File::saveNew(); so we call it even if not following
+            // new redirects.
+            $redir_data = File_redirection::where($given_url);
+            if (is_array($redir_data)) {
+                $redir_url = $redir_data['url'];
+            } elseif (is_string($redir_data)) {
+                $redir_url = $redir_data;
+                $redir_data = array();
+            } else {
+                // TRANS: Server exception thrown when a URL cannot be processed.
+                throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
+            }
 
-                // TODO: max field length
-                if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) {
-                    // Save the File object based on our lookup trace
-                    $file = File::saveNew($redir_data, $given_url);
-                } else {
-                    // This seems kind of messed up... for now skipping this part
-                    // if we're already under a redirect, so we don't go into
-                    // horrible infinite loops if we've been given an unstable
-                    // redirect (where the final destination of the first request
-                    // doesn't match what we get when we ask for it again).
-                    //
-                    // Seen in the wild with clojure.org, which redirects through
-                    // wikispaces for auth and appends session data in the URL params.
-                    $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
-                    File_redirection::saveNew($redir_data, $file->id, $given_url);
-                }
+            if ($redir_url === $given_url || !$followRedirects) {
+                // Save the File object based on our lookup trace
+                $file = File::saveNew($redir_data, $given_url);
+            } else {
+                // This seems kind of messed up... for now skipping this part
+                // if we're already under a redirect, so we don't go into
+                // horrible infinite loops if we've been given an unstable
+                // redirect (where the final destination of the first request
+                // doesn't match what we get when we ask for it again).
+                //
+                // Seen in the wild with clojure.org, which redirects through
+                // wikispaces for auth and appends session data in the URL params.
+                $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
+                File_redirection::saveNew($redir_data, $file->id, $given_url);
             }
 
             if (!$file instanceof File) {
@@ -237,12 +253,7 @@ class File extends Managed_DataObject
 
     static function filename(Profile $profile, $origname, $mimetype)
     {
-        try {
-            $ext = common_supported_mime_to_ext($mimetype);
-        } catch (Exception $e) {
-            // We don't support this mimetype, but let's guess the extension
-            $ext = substr(strrchr($mimetype, '/'), 1);
-        }
+        $ext = self::guessMimeExtension($mimetype);
 
         // Normalize and make the original filename more URL friendly.
         $origname = basename($origname, ".$ext");
@@ -263,6 +274,17 @@ class File extends Managed_DataObject
         return $filename;
     }
 
+    static function guessMimeExtension($mimetype)
+    {
+        try {
+            $ext = common_supported_mime_to_ext($mimetype);
+        } catch (Exception $e) {
+            // We don't support this mimetype, but let's guess the extension
+            $ext = substr(strrchr($mimetype, '/'), 1);
+        }
+        return strtolower($ext);
+    }
+
     /**
      * Validation for as-saved base filenames
      */
@@ -420,7 +442,7 @@ class File extends Managed_DataObject
         }
 
         // throws exception on failure to generate thumbnail
-        $outname = "thumb-{$width}x{$height}-" . $image->filename;
+        $outname = "thumb-{$width}x{$height}-{$image->filename}." . File::guessMimeExtension($image->mimetype);
         $outpath = self::path($outname);
 
         // The boundary box for our resizing
@@ -454,7 +476,11 @@ class File extends Managed_DataObject
 
     public function getPath()
     {
-        return self::path($this->filename);
+        $filepath = self::path($this->filename);
+        if (!file_exists($filepath)) {
+            throw new FileNotFoundException($filepath);
+        }
+        return $filepath;
     }
 
     public function getUrl()
@@ -462,7 +488,7 @@ class File extends Managed_DataObject
         if (!empty($this->filename)) {
             // A locally stored file, so let's generate a URL for our instance.
             $url = self::url($this->filename);
-            if ($url != $this->url) {
+            if (self::hashurl($url) !== $this->urlhash) {
                 // For indexing purposes, in case we do a lookup on the 'url' field.
                 // also we're fixing possible changes from http to https, or paths
                 $this->updateUrl($url);
@@ -474,16 +500,40 @@ class File extends Managed_DataObject
         return $this->url;
     }
 
+    static public function getByUrl($url)
+    {
+        $file = new File();
+        $file->urlhash = self::hashurl($url);
+        if (!$file->find(true)) {
+            throw new NoResultException($file);
+        }
+        return $file;
+    }
+
+    /**
+     * @param   string  $hashstr    String of (preferrably lower case) hexadecimal characters, same as result of 'hash_file(...)'
+     */
+    static public function getByHash($hashstr, $alg=File::FILEHASH_ALG)
+    {
+        $file = new File();
+        $file->filehash = strtolower($hashstr);
+        if (!$file->find(true)) {
+            throw new NoResultException($file);
+        }
+        return $file;
+    }
+
     public function updateUrl($url)
     {
-        $file = File::getKV('url', $url);
+        $file = File::getKV('urlhash', self::hashurl($url));
         if ($file instanceof File) {
             throw new ServerException('URL already exists in DB');
         }
-        $sql = 'UPDATE %1$s SET url=%2$s WHERE url=%3$s;';
+        $sql = 'UPDATE %1$s SET urlhash=%2$s, url=%3$s WHERE urlhash=%4$s;';
         $result = $this->query(sprintf($sql, $this->__table,
+                                             $this->_quote((string)self::hashurl($url)),
                                              $this->_quote((string)$url),
-                                             $this->_quote((string)$this->url)));
+                                             $this->_quote((string)$this->urlhash)));
         if ($result === false) {
             common_log_db_error($this, 'UPDATE', __FILE__);
             throw new ServerException("Could not UPDATE {$this->__table}.url");
@@ -502,9 +552,9 @@ class File extends Managed_DataObject
 
     function blowCache($last=false)
     {
-        self::blow('file:notice-ids:%s', $this->url);
+        self::blow('file:notice-ids:%s', $this->urlhash);
         if ($last) {
-            self::blow('file:notice-ids:%s;last', $this->url);
+            self::blow('file:notice-ids:%s;last', $this->urlhash);
         }
         self::blow('file:notice-count:%d', $this->id);
     }
@@ -582,4 +632,54 @@ class File extends Managed_DataObject
 
         return $title ?: null;
     }
+
+    static public function hashurl($url)
+    {
+        if (empty($url)) {
+            throw new Exception('No URL provided to hash algorithm.');
+        }
+        return hash(self::URLHASH_ALG, $url);
+    }
+
+    static public function beforeSchemaUpdate()
+    {
+        $table = strtolower(get_called_class());
+        $schema = Schema::get();
+        $schemadef = $schema->getTableDef($table);
+
+        // 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
+        if (isset($schemadef['fields']['urlhash']) && isset($schemadef['unique keys']['file_urlhash_key'])) {
+            // We already have the urlhash field, so no need to migrate it.
+            return;
+        }
+        echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
+        // We have to create a urlhash that is _not_ the primary key,
+        // transfer data and THEN run checkSchema
+        $schemadef['fields']['urlhash'] = array (
+                                              'type' => 'varchar',
+                                              'length' => 64,
+                                              'not null' => true,
+                                              'description' => 'sha256 of destination URL (url field)',
+                                            );
+        $schemadef['fields']['url'] = array (
+                                              'type' => 'text',
+                                              'description' => 'destination URL after following possible redirections',
+                                            );
+        unset($schemadef['unique keys']);
+        $schema->ensureTable($table, $schemadef);
+        echo "DONE.\n";
+
+        $classname = ucfirst($table);
+        $tablefix = new $classname;
+        // urlhash is hash('sha256', $url) in the File table
+        echo "Updating urlhash fields in $table table...";
+        // Maybe very MySQL specific :(
+        $tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
+                            $schema->quoteIdentifier($table),
+                            'urlhash',
+                            // The line below is "result of sha256 on column `url`"
+                            'SHA2(url, 256)'));
+        echo "DONE.\n";
+        echo "Resuming core schema upgrade...";
+    }
 }
index 0bcccc6cffbbb52ecd8aa4b0100e2afe6cd93dda..8c64c58a80c79c4ae18b4df999c050b6bbf5cf5b 100644 (file)
@@ -29,7 +29,8 @@ class File_redirection extends Managed_DataObject
     /* the code below is auto generated do not remove the above tag */
 
     public $__table = 'file_redirection';                // table name
-    public $url;                             // varchar(255)  primary_key not_null
+    public $urlhash;                         // varchar(64) primary_key not_null
+    public $url;                             // text
     public $file_id;                         // int(4)
     public $redirections;                    // int(4)
     public $httpcode;                        // int(4)
@@ -42,19 +43,30 @@ class File_redirection extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'url' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'short URL (or any other kind of redirect) for file (id)'),
+                'urlhash' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'sha256 hash of the URL'),
+                'url' => array('type' => 'text', 'description' => 'short URL (or any other kind of redirect) for file (id)'),
                 'file_id' => array('type' => 'int', 'description' => 'short URL for what URL/file'),
                 'redirections' => array('type' => 'int', 'description' => 'redirect count'),
                 'httpcode' => array('type' => 'int', 'description' => 'HTTP status code (20x, 30x, etc.)'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
-            'primary key' => array('url'),
+            'primary key' => array('urlhash'),
             'foreign keys' => array(
                 'file_redirection_file_id_fkey' => array('file' => array('file_id' => 'id')),
             ),
         );
     }
 
+    static public function getByUrl($url)
+    {
+        $file = new File_redirection();
+        $file->urlhash = File::hashurl($url);
+        if (!$file->find(true)) {
+            throw new NoResultException($file);
+        }
+        return $file;
+    }
+
     static function _commonHttp($url, $redirs) {
         $request = new HTTPClient($url);
         $request->setConfig(array(
@@ -161,17 +173,18 @@ class File_redirection extends Managed_DataObject
      */
     public function where($in_url, $discover=true) {
         // let's see if we know this...
-        $a = File::getKV('url', $in_url);
-
-        if (!empty($a)) {
+        try {
+            $a = File::getByUrl($in_url);
             // this is a direct link to $a->url
             return $a->url;
-        } else {
-            $b = File_redirection::getKV('url', $in_url);
-            if (!empty($b)) {
+        } catch (NoResultException $e) {
+            try {
+                $b = File_redirection::getByUrl($in_url);
                 // this is a redirect to $b->file_id
                 $a = File::getKV('id', $b->file_id);
                 return $a->url;
+            } catch (NoResultException $e) {
+                // Oh well, let's keep going
             }
         }
 
@@ -274,6 +287,7 @@ class File_redirection extends Managed_DataObject
             $file_redir = File_redirection::getKV('url', $short_url);
             if (!$file_redir instanceof File_redirection) {
                 $file_redir = new File_redirection;
+                $file_redir->urlhash = File::hashurl($short_url);
                 $file_redir->url = $short_url;
                 $file_redir->file_id = $file_id;
                 $file_redir->insert();
@@ -334,10 +348,53 @@ class File_redirection extends Managed_DataObject
 
     function saveNew($data, $file_id, $url) {
         $file_redir = new File_redirection;
+        $file_redir->urlhash = File::hashurl($short_url);
         $file_redir->url = $url;
         $file_redir->file_id = $file_id;
         $file_redir->redirections = intval($data['redirects']);
         $file_redir->httpcode = intval($data['code']);
         $file_redir->insert();
     }
+
+    static public function beforeSchemaUpdate()
+    {
+        $table = strtolower(get_called_class());
+        $schema = Schema::get();
+        $schemadef = $schema->getTableDef($table);
+
+        // 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
+        if (isset($schemadef['fields']['urlhash']) && in_array('urlhash', $schemadef['primary key'])) {
+            // We already have the urlhash field, so no need to migrate it.
+            return;
+        }
+        echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
+        // We have to create a urlhash that is _not_ the primary key,
+        // transfer data and THEN run checkSchema
+        $schemadef['fields']['urlhash'] = array (
+                                              'type' => 'varchar',
+                                              'length' => 64,
+                                              'not null' => true,
+                                              'description' => 'sha256 hash of the URL',
+                                            );
+        $schemadef['fields']['url'] = array (
+                                              'type' => 'text',
+                                              'description' => 'short URL (or any other kind of redirect) for file (id)',
+                                            );
+        unset($schemadef['primary key']);
+        $schema->ensureTable($table, $schemadef);
+        echo "DONE.\n";
+
+        $classname = ucfirst($table);
+        $tablefix = new $classname;
+        // urlhash is hash('sha256', $url) in the File table
+        echo "Updating urlhash fields in $table table...";
+        // Maybe very MySQL specific :(
+        $tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
+                            $schema->quoteIdentifier($table),
+                            'urlhash',
+                            // The line below is "result of sha256 on column `url`"
+                            'SHA2(url, 256)'));
+        echo "DONE.\n";
+        echo "Resuming core schema upgrade...";
+    }
 }
index 6a92b07d0cda40bfde4e3e9c7a128cc91551e4f4..acd488babaa9b8414864909ece2c0ee9672db876 100644 (file)
@@ -27,8 +27,8 @@ class File_thumbnail extends Managed_DataObject
 {
     public $__table = 'file_thumbnail';                  // table name
     public $file_id;                         // int(4)  primary_key not_null
-    public $url;                             // varchar(255)  unique_key
-    public $filename;                        // varchar(255)
+    public $url;                             // text
+    public $filename;                        // varchar(191)   not 255 because utf8mb4 takes more space
     public $width;                           // int(4)  primary_key
     public $height;                          // int(4)  primary_key
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
@@ -38,8 +38,8 @@ class File_thumbnail extends Managed_DataObject
         return array(
             'fields' => array(
                 'file_id' => array('type' => 'int', 'not null' => true, 'description' => 'thumbnail for what URL/file'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of thumbnail'),
-                'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if stored locally, filename is put here'),
+                'url' => array('type' => 'text', 'description' => 'URL of thumbnail'),
+                'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'if stored locally, filename is put here'),
                 'width' => array('type' => 'int', 'description' => 'width of thumbnail'),
                 'height' => array('type' => 'int', 'description' => 'height of thumbnail'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
@@ -119,7 +119,11 @@ class File_thumbnail extends Managed_DataObject
 
     public function getPath()
     {
-        return self::path($this->filename);
+        $filepath = self::path($this->filename);
+        if (!file_exists($filepath)) {
+            throw new FileNotFoundException($filepath);
+        }
+        return $filepath;
     }
 
     public function getUrl()
index a964d87fdd9baa19e2a1fd024a74f9d3c5745c6c..6176ec43bc3f3a1bf568ce4effb3e66726697219 100644 (file)
@@ -13,7 +13,7 @@ class Foreign_link extends Managed_DataObject
     public $user_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 $credentials;                     // varchar(191)   not 255 because utf8mb4 takes more space
     public $noticesync;                      // tinyint(1)   not_null default_1
     public $friendsync;                      // tinyint(1)   not_null default_2
     public $profilesync;                     // tinyint(1)   not_null default_1
@@ -32,7 +32,7 @@ class Foreign_link extends Managed_DataObject
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'link to user on this system, if exists'),
                 'foreign_id' => array('type' => 'int', 'size' => 'big', 'unsigned' => true, 'not null' => true, 'description' => 'link to user on foreign service, if exists'),
                 'service' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to service'),
-                'credentials' => array('type' => 'varchar', 'length' => 255, 'description' => 'authc credentials, typically a password'),
+                'credentials' => array('type' => 'varchar', 'length' => 191, 'description' => 'authc credentials, typically a password'),
                 'noticesync' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies'),
                 'friendsync' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 2, 'description' => 'friend synchronization, bit 1 = sync outgoing, bit 2 = sync incoming'),
                 'profilesync' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming'),
index df9fd5825d8fd49a4a61c8aaed488f6f7a560ffc..78c1c0cee5bc68cf74022d890259362cea0c4b3a 100644 (file)
@@ -12,7 +12,7 @@ class Foreign_service extends Managed_DataObject
     public $__table = 'foreign_service';                 // table name
     public $id;                              // int(4)  primary_key not_null
     public $name;                            // varchar(32)  unique_key not_null
-    public $description;                     // varchar(255)
+    public $description;                     // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -25,7 +25,7 @@ class Foreign_service extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'numeric key for service'),
                 'name' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'name of the service'),
-                'description' => array('type' => 'varchar', 'length' => 255, 'description' => 'description'),
+                'description' => array('type' => 'varchar', 'length' => 191, 'description' => 'description'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index eeaf817876b7ff8ead28c47cb6e82bc6cf3d621a..c1739d318a08737cedccfec1a8af17b316ee9e71 100644 (file)
@@ -12,8 +12,8 @@ class Foreign_user extends Managed_DataObject
     public $__table = 'foreign_user';                    // table name
     public $id;                              // bigint(8)  primary_key not_null
     public $service;                         // int(4)  primary_key not_null
-    public $uri;                             // varchar(255)  unique_key not_null
-    public $nickname;                        // varchar(255)
+    public $uri;                             // varchar(191)  unique_key not_null   not 255 because utf8mb4 takes more space
+    public $nickname;                        // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -26,8 +26,8 @@ class Foreign_user extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'unique numeric key on foreign service'),
                 'service' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to service'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'identifying URI'),
-                'nickname' => array('type' => 'varchar', 'length' => 255, 'description' => 'nickname on foreign service'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'identifying URI'),
+                'nickname' => array('type' => 'varchar', 'length' => 191, 'description' => 'nickname on foreign service'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index 14f417758da21890fecf21a944cdc77891c3beb8..392440222b066d6c153c2a9704acb88f4ade03a1 100644 (file)
@@ -12,7 +12,7 @@ class Group_member extends Managed_DataObject
     public $group_id;                        // int(4)  primary_key not_null
     public $profile_id;                      // int(4)  primary_key not_null
     public $is_admin;                        // tinyint(1)
-    public $uri;                             // varchar(255)
+    public $uri;                             // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -26,7 +26,7 @@ class Group_member extends Managed_DataObject
                 'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to user_group'),
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
                 'is_admin' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'is this user an admin?'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index a40bd0f330a5b96d8afaba56f3d7743a79efc9c6..ca03bb7aa10fe4dfa868fd8ccce5dc99c046054c 100644 (file)
@@ -12,7 +12,7 @@ class Invitation extends Managed_DataObject
     public $__table = 'invitation';                      // table name
     public $code;                            // varchar(32)  primary_key not_null
     public $user_id;                         // int(4)   not_null
-    public $address;                         // varchar(255)  multiple_key not_null
+    public $address;                         // varchar(191)  multiple_key not_null   not 255 because utf8mb4 takes more space
     public $address_type;                    // varchar(8)  multiple_key not_null
     public $registered_user_id;              // int(4)   not_null
     public $created;                         // datetime()   not_null
@@ -34,7 +34,7 @@ class Invitation extends Managed_DataObject
             'fields' => array(
                 'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'random code for an invitation'),
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'who sent the invitation'),
-                'address' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'invitation sent to'),
+                'address' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'invitation sent to'),
                 'address_type' => array('type' => 'varchar', 'length' => 8, 'not null' => true, 'description' => 'address type ("email", "xmpp", "sms")'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'registered_user_id' => array('type' => 'int', 'not null' => false, 'description' => 'if the invitation is converted, who the new user is'),
index 3690ecc0446a7d3617c4f82d9a680cd4531ebd1b..a84147395348308ae96b5e818df92206acd1cd40 100644 (file)
@@ -32,7 +32,7 @@ class Location_namespace extends Managed_DataObject
 
     public $__table = 'location_namespace';              // table name
     public $id;                              // int(4)  primary_key not_null
-    public $description;                     // varchar(255)
+    public $description;                     // varchar(191)
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -44,7 +44,7 @@ class Location_namespace extends Managed_DataObject
         return array(
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'identity for this namespace'),
-                'description' => array('type' => 'varchar', 'length' => 255, 'description' => 'description of the namespace'),
+                'description' => array('type' => 'varchar', 'length' => 191, 'description' => 'description of the namespace'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index a628b8bee3aa1834879ecae689e4c9ca40ce2940..b324984b7f8e7512d4c8b77606654ca6b10b8ae2 100644 (file)
@@ -299,6 +299,11 @@ abstract class Managed_DataObject extends Memcached_DataObject
         return $ckeys;
     }
 
+    public function escapedTableName()
+    {
+        return common_database_tablename($this->tableName());
+    }
+
     /**
      * Returns an ID, checked that it is set and reasonably valid
      *
@@ -391,4 +396,9 @@ abstract class Managed_DataObject extends Memcached_DataObject
         // @FIXME return true only if something changed (otherwise 0)
         return $result;
     }
+
+    static public function beforeSchemaUpdate()
+    {
+        // NOOP
+    }
 }
index 2bd9581cf6dcf17fe4454f8244c7bc4d2942c7da..3f1945205afcb48fd0cde54beb4257ed095b2791 100644 (file)
@@ -734,7 +734,7 @@ class Memcached_DataObject extends Safe_DataObject
         return $string;
     }
 
-    // We overload so that 'SET NAMES "utf8"' is called for
+    // We overload so that 'SET NAMES "utf8mb4"' is called for
     // each connection
 
     function _connect()
@@ -784,9 +784,9 @@ class Memcached_DataObject extends Safe_DataObject
                 $conn = $DB->connection;
                 if (!empty($conn)) {
                     if ($DB instanceof DB_mysqli || $DB instanceof MDB2_Driver_mysqli) {
-                        mysqli_set_charset($conn, 'utf8');
+                        mysqli_set_charset($conn, 'utf8mb4');
                     } else if ($DB instanceof DB_mysql || $DB instanceof MDB2_Driver_mysql) {
-                        mysql_set_charset('utf8', $conn);
+                        mysql_set_charset('utf8mb4', $conn);
                     }
                 }
             }
index 9d8dfece044b8ee740c41fefca852800e2828219..d37aade4a8f85063c045142a4670a0a00f43af4b 100644 (file)
@@ -10,7 +10,7 @@ class Nonce extends Managed_DataObject
     /* the code below is auto generated do not remove the above tag */
 
     public $__table = 'nonce';                           // table name
-    public $consumer_key;                    // varchar(255)  primary_key not_null
+    public $consumer_key;                    // varchar(191)  primary_key not_null   not 255 because utf8mb4 takes more space
     public $tok;                             // char(32)
     public $nonce;                           // char(32)  primary_key not_null
     public $ts;                              // datetime()  primary_key not_null
@@ -39,7 +39,7 @@ class Nonce extends Managed_DataObject
         return array(
             'description' => 'OAuth nonce record',
             'fields' => array(
-                'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
+                'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
                 'tok' => array('type' => 'char', 'length' => 32, 'description' => 'buggy old value, ignored'),
                 'nonce' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'nonce'),
                 'ts' => array('type' => 'datetime', 'not null' => true, 'description' => 'timestamp sent'),
index a69efc45aeadae79c43fcc92d763278a6192caab..c631c1fcc6768dd690bb449c8115096c1806f644 100644 (file)
@@ -55,10 +55,10 @@ class Notice extends Managed_DataObject
     public $__table = 'notice';                          // table name
     public $id;                              // int(4)  primary_key not_null
     public $profile_id;                      // int(4)  multiple_key not_null
-    public $uri;                             // varchar(255)  unique_key
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $content;                         // text
     public $rendered;                        // text
-    public $url;                             // varchar(255)
+    public $url;                             // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime  multiple_key not_null default_0000-00-00%2000%3A00%3A00
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
     public $reply_to;                        // int(4)
@@ -70,8 +70,8 @@ class Notice extends Managed_DataObject
     public $location_id;                     // int(4)
     public $location_ns;                     // int(4)
     public $repeat_of;                       // int(4)
-    public $verb;                            // varchar(255)
-    public $object_type;                     // varchar(255)
+    public $verb;                            // varchar(191)   not 255 because utf8mb4 takes more space
+    public $object_type;                     // varchar(191)   not 255 because utf8mb4 takes more space
     public $scope;                           // int(4)
 
     /* the code above is auto generated do not remove the tag below */
@@ -83,10 +83,10 @@ class Notice extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'who made the update'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
                 'content' => array('type' => 'text', 'description' => 'update content', 'collate' => 'utf8_general_ci'),
                 'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
+                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
                 'reply_to' => array('type' => 'int', 'description' => 'notice replied to (usually a guess)'),
@@ -98,8 +98,8 @@ class Notice extends Managed_DataObject
                 'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
                 'location_ns' => array('type' => 'int', 'description' => 'namespace for location'),
                 'repeat_of' => array('type' => 'int', 'description' => 'notice this is a repeat of'),
-                'object_type' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'),
-                'verb' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI representing activity streams verb', 'default' => 'http://activitystrea.ms/schema/1.0/post'),
+                'object_type' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'),
+                'verb' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams verb', 'default' => 'http://activitystrea.ms/schema/1.0/post'),
                 'scope' => array('type' => 'int',
                                  'description' => 'bit map for distribution scope; 0 = everywhere; 1 = this server only; 2 = addressees; 4 = followers; null = default'),
             ),
@@ -128,7 +128,7 @@ class Notice extends Managed_DataObject
 
         return $def;
     }
-       
+
     /* Notice types */
     const LOCAL_PUBLIC    =  1;
     const REMOTE          =  0;
@@ -142,7 +142,7 @@ class Notice extends Managed_DataObject
     const FOLLOWER_SCOPE  = 8;
 
     protected $_profile = array();
-    
+
     /**
      * Will always return a profile, if anything fails it will
      * (through _setProfile) throw a NoProfileException.
@@ -157,7 +157,7 @@ class Notice extends Managed_DataObject
         }
         return $this->_profile[$this->profile_id];
     }
-    
+
     public function _setProfile(Profile $profile=null)
     {
         if (!$profile instanceof Profile) {
@@ -268,7 +268,7 @@ class Notice extends Managed_DataObject
         }
         return $title;
     }
-    
+
     public function getContent()
     {
         return $this->content;
@@ -674,7 +674,7 @@ class Notice extends Managed_DataObject
                 $notice->insert();  // throws exception on failure
                 // If it's not part of a conversation, it's
                 // the beginning of a new conversation.
-                if (empty($notice->conversation)) { 
+                if (empty($notice->conversation)) {
                     $orig = clone($notice);
                     // $act->context->conversation will be null if it was not provided
                     $conv = Conversation::create($notice, $options['conversation']);
@@ -777,7 +777,7 @@ class Notice extends Managed_DataObject
                           'distribute' => true);
 
         // options will have default values when nothing has been supplied
-        $options = array_merge($defaults, $options); 
+        $options = array_merge($defaults, $options);
         foreach (array_keys($defaults) as $key) {
             // Only convert the keynames we specify ourselves from 'defaults' array into variables
             $$key = $options[$key];
@@ -957,7 +957,7 @@ class Notice extends Managed_DataObject
             // Prepare inbox delivery, may be queued to background.
             $stored->distribute();
         }
-        
+
         return $stored;
     }
 
@@ -1067,13 +1067,9 @@ class Notice extends Managed_DataObject
         }
 
         $args = func_get_args();
-
         $format = array_shift($args);
-
         $keyPart = vsprintf($format, $args);
-
         $cacheKey = Cache::key($keyPart);
-        
         $c->delete($cacheKey);
 
         // delete the "last" stream, too, if this notice is
@@ -1187,24 +1183,20 @@ class Notice extends Managed_DataObject
     }
 
        protected $_attachments = array();
-       
+
     function attachments() {
                if (isset($this->_attachments[$this->id])) {
             return $this->_attachments[$this->id];
         }
-               
+
         $f2ps = File_to_post::listGet('post_id', array($this->id));
-               
                $ids = array();
-               
                foreach ($f2ps[$this->id] as $f2p) {
-            $ids[] = $f2p->file_id;    
+            $ids[] = $f2p->file_id;
         }
-               
-               $files = File::multiGet('id', $ids);
 
+               $files = File::multiGet('id', $ids);
                $this->_attachments[$this->id] = $files->fetchAll();
-               
         return $this->_attachments[$this->id];
     }
 
@@ -1286,7 +1278,7 @@ class Notice extends Managed_DataObject
             $root->free();
             return $root;
         }
-        
+
         if (is_null($profile)) {
             $keypart = sprintf('notice:conversation_root:%d:null', $this->id);
         } else {
@@ -1294,7 +1286,7 @@ class Notice extends Managed_DataObject
                                $this->id,
                                $profile->id);
         }
-            
+
         $root = self::cacheGet($keypart);
 
         if ($root !== false && $root->inScope($profile)) {
@@ -1707,9 +1699,9 @@ class Notice extends Managed_DataObject
     function getReplyProfiles()
     {
         $ids = $this->getReplies();
-        
+
         $profiles = Profile::multiGet('id', $ids);
-        
+
         return $profiles->fetchAll();
     }
 
@@ -1747,9 +1739,9 @@ class Notice extends Managed_DataObject
      *
      * @return array of Group objects
      */
-    
+
     protected $_groups = array();
-    
+
     function getGroups()
     {
         // Don't save groups for repeats
@@ -1757,27 +1749,24 @@ class Notice extends Managed_DataObject
         if (!empty($this->repeat_of)) {
             return array();
         }
-        
+
         if (isset($this->_groups[$this->id])) {
             return $this->_groups[$this->id];
         }
-        
+
         $gis = Group_inbox::listGet('notice_id', array($this->id));
 
         $ids = array();
 
-               foreach ($gis[$this->id] as $gi)
-               {
+               foreach ($gis[$this->id] as $gi) {
                    $ids[] = $gi->group_id;
                }
-               
+
                $groups = User_group::multiGet('id', $ids);
-               
                $this->_groups[$this->id] = $groups->fetchAll();
-               
                return $this->_groups[$this->id];
     }
-    
+
     function _setGroups($groups)
     {
         $this->_groups[$this->id] = $groups;
@@ -2159,7 +2148,7 @@ class Notice extends Managed_DataObject
             // Unfortunately this is likely to lose tags or URLs
             // at the end of long notices.
             $content = mb_substr($content, 0, $maxlen - 4) . ' ...';
-        }     
+        }
 
 
         // Scope is same as this one's
@@ -2687,89 +2676,69 @@ class Notice extends Managed_DataObject
             $scope = self::defaultScope();
         }
 
-        // If there's no scope, anyone (even anon) is in scope.
-
-        if ($scope == 0) { // Not private
-
+        if ($scope == 0 && !$this->getProfile()->isPrivateStream()) { // Not scoping, so it is public.
             return !$this->isHiddenSpam($profile);
+        }
 
-        } else { // Private, somehow
-
-            // If there's scope, anon cannot be in scope
+        // If there's scope, anon cannot be in scope
+        if (empty($profile)) {
+            return false;
+        }
 
-            if (empty($profile)) {
-                return false;
-            }
+        // Author is always in scope
+        if ($this->profile_id == $profile->id) {
+            return true;
+        }
 
-            // Author is always in scope
+        // Only for users on this site
+        if (($scope & Notice::SITE_SCOPE) && !$profile->isLocal()) {
+            return false;
+        }
 
-            if ($this->profile_id == $profile->id) {
-                return true;
-            }
+        // Only for users mentioned in the notice
+        if ($scope & Notice::ADDRESSEE_SCOPE) {
 
-            // Only for users on this site
+            $reply = Reply::pkeyGet(array('notice_id' => $this->id,
+                                         'profile_id' => $profile->id));
 
-            if (($scope & Notice::SITE_SCOPE) && !$profile->isLocal()) {
+            if (!$reply instanceof Reply) {
                 return false;
             }
+        }
 
-            // Only for users mentioned in the notice
-
-            if ($scope & Notice::ADDRESSEE_SCOPE) {
-
-                $reply = Reply::pkeyGet(array('notice_id' => $this->id,
-                                             'profile_id' => $profile->id));
-                                                                                
-                if (!$reply instanceof Reply) {
-                    return false;
-                }
-            }
-
-            // Only for members of the given group
-
-            if ($scope & Notice::GROUP_SCOPE) {
+        // Only for members of the given group
+        if ($scope & Notice::GROUP_SCOPE) {
 
-                // XXX: just query for the single membership
+            // XXX: just query for the single membership
 
-                $groups = $this->getGroups();
+            $groups = $this->getGroups();
 
-                $foundOne = false;
+            $foundOne = false;
 
-                foreach ($groups as $group) {
-                    if ($profile->isMember($group)) {
-                        $foundOne = true;
-                        break;
-                    }
-                }
-
-                if (!$foundOne) {
-                    return false;
+            foreach ($groups as $group) {
+                if ($profile->isMember($group)) {
+                    $foundOne = true;
+                    break;
                 }
             }
 
-            // Only for followers of the author
-
-            $author = null;
+            if (!$foundOne) {
+                return false;
+            }
+        }
 
-            if ($scope & Notice::FOLLOWER_SCOPE) {
+        if ($scope & Notice::FOLLOWER_SCOPE || $this->getProfile()->isPrivateStream()) {
 
-                try {
-                    $author = $this->getProfile();
-                } catch (Exception $e) {
-                    return false;
-                }
-        
-                if (!Subscription::exists($profile, $author)) {
-                    return false;
-                }
+            if (!Subscription::exists($profile, $this->getProfile())) {
+                return false;
             }
-
-            return !$this->isHiddenSpam($profile);
         }
+
+        return !$this->isHiddenSpam($profile);
     }
 
     function isHiddenSpam($profile) {
-        
+
         // Hide posts by silenced users from everyone but moderators.
 
         if (common_config('notice', 'hidespam')) {
@@ -2819,7 +2788,7 @@ class Notice extends Managed_DataObject
         $skip = array('_profile', '_groups', '_attachments', '_faves', '_replies', '_repeats');
         return array_diff($vars, $skip);
     }
-    
+
     static function defaultScope()
     {
        $scope = common_config('notice', 'defaultscope');
@@ -2836,7 +2805,6 @@ class Notice extends Managed_DataObject
        static function fillProfiles($notices)
        {
                $map = self::getProfiles($notices);
-               
                foreach ($notices as $entry=>$notice) {
             try {
                        if (array_key_exists($notice->profile_id, $map)) {
@@ -2847,42 +2815,35 @@ class Notice extends Managed_DataObject
                 unset($notices[$entry]);
             }
                }
-               
+
                return array_values($map);
        }
-       
+
        static function getProfiles(&$notices)
        {
                $ids = array();
                foreach ($notices as $notice) {
                        $ids[] = $notice->profile_id;
                }
-               
                $ids = array_unique($ids);
-               
-               return Profile::pivotGet('id', $ids); 
+               return Profile::pivotGet('id', $ids);
        }
-       
+
        static function fillGroups(&$notices)
        {
         $ids = self::_idsOf($notices);
-               
         $gis = Group_inbox::listGet('notice_id', $ids);
-               
         $gids = array();
 
-               foreach ($gis as $id => $gi)
-               {
+               foreach ($gis as $id => $gi) {
                    foreach ($gi as $g)
                    {
                        $gids[] = $g->group_id;
                    }
                }
-               
+
                $gids = array_unique($gids);
-               
                $group = User_group::pivotGet('id', $gids);
-               
                foreach ($notices as $notice)
                {
                        $grps = array();
@@ -2906,21 +2867,16 @@ class Notice extends Managed_DataObject
     static function fillAttachments(&$notices)
     {
         $ids = self::_idsOf($notices);
-
         $f2pMap = File_to_post::listGet('post_id', $ids);
-               
                $fileIds = array();
-               
                foreach ($f2pMap as $noticeId => $f2ps) {
             foreach ($f2ps as $f2p) {
-                $fileIds[] = $f2p->file_id;    
+                $fileIds[] = $f2p->file_id;
             }
         }
 
         $fileIds = array_unique($fileIds);
-
                $fileMap = File::pivotGet('id', $fileIds);
-
                foreach ($notices as $notice)
                {
                        $files = array();
index 6f3d2e5634d4249dc5632de95f6196b9575bac5a..f31d4411ffbd5d4f975fb8f1ecb591391b540711 100644 (file)
@@ -11,8 +11,8 @@ class Notice_source extends Managed_DataObject
 
     public $__table = 'notice_source';                   // table name
     public $code;                            // varchar(32)  primary_key not_null
-    public $name;                            // varchar(255)   not_null
-    public $url;                             // varchar(255)   not_null
+    public $name;                            // varchar(191)   not_null   not 255 because utf8mb4 takes more space
+    public $url;                             // varchar(191)   not_null   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -24,8 +24,8 @@ class Notice_source extends Managed_DataObject
         return array(
             'fields' => array(
                 'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'source code'),
-                'name' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'name of the source'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'url to link to'),
+                'name' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the source'),
+                'url' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'url to link to'),
                 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'date this record was created'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index b29fdfe41b1fb059cb79ae409010950a44be1650..9cf3f5e108849b859018c6520b10c5fc0967b6e8 100644 (file)
@@ -12,14 +12,14 @@ class Oauth_application extends Managed_DataObject
     public $__table = 'oauth_application';               // table name
     public $id;                              // int(4)  primary_key not_null
     public $owner;                           // int(4)   not_null
-    public $consumer_key;                    // varchar(255)   not_null
-    public $name;                            // varchar(255)   not_null
-    public $description;                     // varchar(255)
-    public $icon;                            // varchar(255)   not_null
-    public $source_url;                      // varchar(255)
-    public $organization;                    // varchar(255)
-    public $homepage;                        // varchar(255)
-    public $callback_url;                    // varchar(255)   not_null
+    public $consumer_key;                    // varchar(191)   not_null   not 255 because utf8mb4 takes more space
+    public $name;                            // varchar(191)   not_null   not 255 because utf8mb4 takes more space
+    public $description;                     // varchar(191)              not 255 because utf8mb4 takes more space
+    public $icon;                            // varchar(191)              not_null   not 255 because utf8mb4 takes more space
+    public $source_url;                      // varchar(191)              not 255 because utf8mb4 takes more space
+    public $organization;                    // varchar(191)              not 255 because utf8mb4 takes more space
+    public $homepage;                        // varchar(191)              not 255 because utf8mb4 takes more space
+    public $callback_url;                    // varchar(191)   not_null   not 255 because utf8mb4 takes more space
     public $type;                            // tinyint(1)
     public $access_type;                     // tinyint(1)
     public $created;                         // datetime   not_null
@@ -43,12 +43,12 @@ class Oauth_application extends Managed_DataObject
     static function maxDesc()
     {
         // This used to default to textlimit or allow unlimited descriptions,
-        // but this isn't part of a notice and the field's limited to 255 chars
-        // in the DB, so those seem silly.
+        // but this isn't part of a notice and the field's limited to 191 chars
+        // in the DB, so those seem silly. (utf8mb4 takes up more space, so can't use 255)
         //
-        // Now just defaulting to 255 max unless a smaller application desclimit
+        // Now just defaulting to 191 max unless a smaller application desclimit
         // is actually set. Setting to 0 will use the maximum.
-        $max = 255;
+        $max = 191;
         $desclimit = intval(common_config('application', 'desclimit'));
         if ($desclimit > 0 && $desclimit < $max) {
             return $desclimit;
@@ -163,14 +163,14 @@ class Oauth_application extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
                 'owner' => array('type' => 'int', 'not null' => true, 'description' => 'owner of the application'),
-                'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'application consumer key'),
-                'name' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'name of the application'),
-                'description' => array('type' => 'varchar', 'length' => 255, 'description' => 'description of the application'),
-                'icon' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'application icon'),
-                'source_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'application homepage - used for source link'),
-                'organization' => array('type' => 'varchar', 'length' => 255, 'description' => 'name of the organization running the application'),
-                'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'homepage for the organization'),
-                'callback_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'url to redirect to after authentication'),
+                'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'application consumer key'),
+                'name' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the application'),
+                'description' => array('type' => 'varchar', 'length' => 191, 'description' => 'description of the application'),
+                'icon' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'application icon'),
+                'source_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'application homepage - used for source link'),
+                'organization' => array('type' => 'varchar', 'length' => 191, 'description' => 'name of the organization running the application'),
+                'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'homepage for the organization'),
+                'callback_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'url to redirect to after authentication'),
                 'type' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'type of app, 1 = browser, 2 = desktop'),
                 'access_type' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'default access type, bit 1 = read, bit 2 = write'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
index 007e4d1db6656be08b574886f17352f16a462109..60b2e8fa2c505caaca88bc52aeb707cca2aeb2f3 100644 (file)
@@ -13,7 +13,7 @@ class Oauth_application_user extends Managed_DataObject
     public $profile_id;                      // int(4)  primary_key not_null
     public $application_id;                  // int(4)  primary_key not_null
     public $access_type;                     // tinyint(1)
-    public $token;                           // varchar(255)
+    public $token;                           // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime   not_null
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
 
@@ -27,7 +27,7 @@ class Oauth_application_user extends Managed_DataObject
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'user of the application'),
                 'application_id' => array('type' => 'int', 'not null' => true, 'description' => 'id of the application'),
                 'access_type' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'access type, bit 1 = read, bit 2 = write'),
-                'token' => array('type' => 'varchar', 'length' => 255, 'description' => 'request or access token'),
+                'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'request or access token'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index ec5eae3064016b1778de2741278289034eae41cc..83bc0d80541fe2b9dbd0b3fa047d59156e73a7e2 100644 (file)
@@ -12,7 +12,7 @@ class Oauth_token_association extends Managed_DataObject
     public $__table = 'oauth_token_association';          // table name
     public $profile_id;                      // int(4)  primary_key not_null
     public $application_id;                  // int(4)  primary_key not_null
-    public $token;                           // varchar(255) primary key not null
+    public $token;                           // varchar(191) primary key not null   not 255 because utf8mb4 takes more space
     public $created;                         // datetime   not_null
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
 
@@ -43,7 +43,7 @@ class Oauth_token_association extends Managed_DataObject
             'fields' => array(
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'associated user'),
                 'application_id' => array('type' => 'int', 'not null' => true, 'description' => 'the application'),
-                'token' => array('type' => 'varchar', 'length' => '255', 'not null' => true, 'description' => 'token used for this association'),
+                'token' => array('type' => 'varchar', 'length' => '191', 'not null' => true, 'description' => 'token used for this association'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index 0b608fbb24883164733d90560d8c9a8c1c5cbbcc..a944d5b4d23f5768c6d4ffcd4ade2b21b61b79a8 100644 (file)
@@ -30,11 +30,11 @@ class Profile extends Managed_DataObject
     public $__table = 'profile';                         // table name
     public $id;                              // int(4)  primary_key not_null
     public $nickname;                        // varchar(64)  multiple_key not_null
-    public $fullname;                        // varchar(255)  multiple_key
-    public $profileurl;                      // varchar(255)
-    public $homepage;                        // varchar(255)  multiple_key
+    public $fullname;                        // varchar(191)  multiple_key   not 255 because utf8mb4 takes more space
+    public $profileurl;                      // varchar(191)                 not 255 because utf8mb4 takes more space
+    public $homepage;                        // varchar(191)  multiple_key   not 255 because utf8mb4 takes more space
     public $bio;                             // text()  multiple_key
-    public $location;                        // varchar(255)  multiple_key
+    public $location;                        // varchar(191)  multiple_key   not 255 because utf8mb4 takes more space
     public $lat;                             // decimal(10,7)
     public $lon;                             // decimal(10,7)
     public $location_id;                     // int(4)
@@ -49,11 +49,11 @@ class Profile extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
                 'nickname' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username', 'collate' => 'utf8_general_ci'),
-                'fullname' => array('type' => 'varchar', 'length' => 255, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
-                'profileurl' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL, cached so we dont regenerate'),
-                'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
+                'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
+                'profileurl' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
+                'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
                 'bio' => array('type' => 'text', 'description' => 'descriptive biography', 'collate' => 'utf8_general_ci'),
-                'location' => array('type' => 'varchar', 'length' => 255, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
+                'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
                 'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'),
                 'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'),
                 'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
@@ -1451,6 +1451,12 @@ class Profile extends Managed_DataObject
         return $feed;
     }
 
+    public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
+    {
+        // TRANS: Exception thrown when trying view "repeated to me".
+        throw new Exception(_('Not implemented since inbox change.'));
+    }
+
     /*
      * Get a Profile object by URI. Will call external plugins for help
      * using the event StartGetProfileFromURI.
@@ -1566,6 +1572,15 @@ class Profile extends Managed_DataObject
         return $this->getUser()->shortenLinks($text, $always);
     }
 
+    public function isPrivateStream()
+    {
+        // We only know of public remote users as of yet...
+        if (!$this->isLocal()) {
+            return false;
+        }
+        return $this->getUser()->private_stream ? true : false;
+    }
+
     public function delPref($namespace, $topic) {
         return Profile_prefs::setData($this, $namespace, $topic, null);
     }
index 0ad8106e3187d10b88da3dcfe0d45857d146c2f5..2b3d2aa5ad4dd87e73f6d86bf94bb0f2886cb392 100644 (file)
@@ -43,8 +43,8 @@ class Profile_list extends Managed_DataObject
     public $private;                         // tinyint(1)
     public $created;                         // datetime   not_null default_0000-00-00%2000%3A00%3A00
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
-    public $uri;                             // varchar(255)  unique_key
-    public $mainpage;                        // varchar(255)
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
+    public $mainpage;                        // varchar(191)   not 255 because utf8mb4 takes more space
     public $tagged_count;                    // smallint
     public $subscriber_count;                // smallint
 
@@ -64,8 +64,8 @@ class Profile_list extends Managed_DataObject
                 'created' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was added'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was modified'),
 
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
-                'mainpage' => array('type' => 'varchar', 'length' => 255, 'description' => 'page to link to'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
+                'mainpage' => array('type' => 'varchar', 'length' => 191, 'description' => 'page to link to'),
                 'tagged_count' => array('type' => 'int', 'default' => 0, 'description' => 'number of people tagged with this tag by this user'),
                 'subscriber_count' => array('type' => 'int', 'default' => 0, 'description' => 'number of subscribers to this tag'),
             ),
index ee0fa0e27cce09c96a5e2d568a9c9558397bf518..27034390f848d4293ff35f701b95d2ac2ef57a77 100644 (file)
@@ -31,8 +31,8 @@ class Profile_prefs extends Managed_DataObject
 {
     public $__table = 'profile_prefs';       // table name
     public $profile_id;                      // int(4)  primary_key not_null
-    public $namespace;                       // varchar(255)  not_null
-    public $topic;                           // varchar(255)  not_null
+    public $namespace;                       // varchar(191)  not_null
+    public $topic;                           // varchar(191)  not_null
     public $data;                            // text
     public $created;                         // datetime   not_null default_0000-00-00%2000%3A00%3A00
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
@@ -42,8 +42,8 @@ class Profile_prefs extends Managed_DataObject
         return array(
             'fields' => array(
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'user'),
-                'namespace' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'namespace, like pluginname or category'),
-                'topic' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'preference key, i.e. description, age...'),
+                'namespace' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'namespace, like pluginname or category'),
+                'topic' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'preference key, i.e. description, age...'),
                 'data' => array('type' => 'blob', 'description' => 'topic data, may be anything'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index 7d3a5fc0ca22a5432cf5baf8393e46d6b7fd2fb3..d37cf42d970a0b2928e1948da732efed0bb73795 100644 (file)
@@ -12,7 +12,7 @@ class Sms_carrier extends Managed_DataObject
     public $__table = 'sms_carrier';                     // table name
     public $id;                              // int(4)  primary_key not_null
     public $name;                            // varchar(64)  unique_key
-    public $email_pattern;                   // varchar(255)   not_null
+    public $email_pattern;                   // varchar(191)   not_null   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -30,7 +30,7 @@ class Sms_carrier extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'primary key for SMS carrier'),
                 'name' => array('type' => 'varchar', 'length' => 64, 'description' => 'name of the carrier'),
-                'email_pattern' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'sprintf pattern for making an email address from a phone number'),
+                'email_pattern' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'sprintf pattern for making an email address from a phone number'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index ffbf9d5a3c0efd0c9c708739aff459a9702bc117..3498b4bd24b4ae18a0a9f5213ff9666beff92977 100644 (file)
@@ -29,15 +29,15 @@ class Status_network extends Safe_DataObject
     public $__table = 'status_network';                  // table name
     public $site_id;                         // int(4) primary_key not_null
     public $nickname;                        // varchar(64)   unique_key not_null
-    public $hostname;                        // varchar(255)  unique_key
-    public $pathname;                        // varchar(255)  unique_key
-    public $dbhost;                          // varchar(255)
-    public $dbuser;                          // varchar(255)
-    public $dbpass;                          // varchar(255)
-    public $dbname;                          // varchar(255)
-    public $sitename;                        // varchar(255)
-    public $theme;                           // varchar(255)
-    public $logo;                            // varchar(255)
+    public $hostname;                        // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
+    public $pathname;                        // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
+    public $dbhost;                          // varchar(191)               not 255 because utf8mb4 takes more space
+    public $dbuser;                          // varchar(191)               not 255 because utf8mb4 takes more space
+    public $dbpass;                          // varchar(191)               not 255 because utf8mb4 takes more space
+    public $dbname;                          // varchar(191)               not 255 because utf8mb4 takes more space
+    public $sitename;                        // varchar(191)               not 255 because utf8mb4 takes more space
+    public $theme;                           // varchar(191)               not 255 because utf8mb4 takes more space
+    public $logo;                            // varchar(191)               not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
index 4d7eb524dcf8d89da61e4ba15d9a2bac39d7b7cc..5c5101ad1d1bb430ed0493037782b0ed4c0c87b9 100644 (file)
@@ -32,9 +32,9 @@ class Subscription extends Managed_DataObject
     public $subscribed;                      // int(4)  primary_key not_null
     public $jabber;                          // tinyint(1)   default_1
     public $sms;                             // tinyint(1)   default_1
-    public $token;                           // varchar(255)
-    public $secret;                          // varchar(255)
-    public $uri;                             // varchar(255)
+    public $token;                           // varchar(191)   not 255 because utf8mb4 takes more space
+    public $secret;                          // varchar(191)   not 255 because utf8mb4 takes more space
+    public $uri;                             // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -46,9 +46,9 @@ class Subscription extends Managed_DataObject
                 'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'profile being listened to'),
                 'jabber' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver jabber messages'),
                 'sms' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver sms messages'),
-                'token' => array('type' => 'varchar', 'length' => 255, 'description' => 'authorization token'),
-                'secret' => array('type' => 'varchar', 'length' => 255, 'description' => 'token secret'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
+                'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'authorization token'),
+                'secret' => array('type' => 'varchar', 'length' => 191, 'description' => 'token secret'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
@@ -232,9 +232,25 @@ class Subscription extends Managed_DataObject
 
     static function exists(Profile $subscriber, Profile $other)
     {
-        $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id,
-                                           'subscribed' => $other->id));
-        return ($sub instanceof Subscription);
+        try {
+            $sub = self::getSubscription($subscriber, $other);
+        } catch (NoResultException $e) {
+            return false;
+        }
+
+        return true;
+    }
+
+    static function getSubscription(Profile $subscriber, Profile $other)
+    {
+        // This is essentially a pkeyGet but we have an object to return in NoResultException
+        $sub = new Subscription();
+        $sub->subscriber = $subscriber->id;
+        $sub->subscribed = $other->id;
+        if (!$sub->find(true)) {
+            throw new NoResultException($sub);
+        }
+        return $sub;
     }
 
     function asActivity()
index 8d8a4d1c113db4719ff9db2fc9e139ef65ca5f7d..89b3f4ecf1de24f646a3e4eb039e6b64616c8b60 100644 (file)
@@ -10,13 +10,13 @@ class Token extends Managed_DataObject
     /* the code below is auto generated do not remove the above tag */
 
     public $__table = 'token';                           // table name
-    public $consumer_key;                    // varchar(255)  primary_key not_null
+    public $consumer_key;                    // varchar(191)  primary_key not_null   not 255 because utf8mb4 takes more space
     public $tok;                             // char(32)  primary_key not_null
     public $secret;                          // char(32)   not_null
     public $type;                            // tinyint(1)   not_null
     public $state;                           // tinyint(1)
-    public $verifier;                        // varchar(255)
-    public $verified_callback;               // varchar(255)
+    public $verifier;                        // varchar(191)   not 255 because utf8mb4 takes more space
+    public $verified_callback;               // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -27,13 +27,13 @@ class Token extends Managed_DataObject
         return array(
             'description' => 'OAuth token record',
             'fields' => array(
-                'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
+                'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
                 'tok' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'identifying value'),
                 'secret' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'secret value'),
                 'type' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'request or access'),
                 'state' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'for requests, 0 = initial, 1 = authorized, 2 = used'),
-                'verifier' => array('type' => 'varchar', 'length' => 255, 'description' => 'verifier string for OAuth 1.0a'),
-                'verified_callback' => array('type' => 'varchar', 'length' => 255, 'description' => 'verified callback URL for OAuth 1.0a'),
+                'verifier' => array('type' => 'varchar', 'length' => 191, 'description' => 'verifier string for OAuth 1.0a'),
+                'verified_callback' => array('type' => 'varchar', 'length' => 191, 'description' => 'verified callback URL for OAuth 1.0a'),
 
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index 7a19ae3a0a04cbf9e39cdb5d724106292078d78b..764574d2254d7765d44ada464eb486ed4d5d5500 100644 (file)
@@ -34,9 +34,9 @@ class User extends Managed_DataObject
     public $__table = 'user';                            // table name
     public $id;                              // int(4)  primary_key not_null
     public $nickname;                        // varchar(64)  unique_key
-    public $password;                        // varchar(255)
-    public $email;                           // varchar(255)  unique_key
-    public $incomingemail;                   // varchar(255)  unique_key
+    public $password;                        // varchar(191)               not 255 because utf8mb4 takes more space
+    public $email;                           // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
+    public $incomingemail;                   // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $emailnotifysub;                  // tinyint(1)   default_1
     public $emailnotifyfav;                  // tinyint(1)   default_1
     public $emailnotifynudge;                // tinyint(1)   default_1
@@ -50,8 +50,8 @@ class User extends Managed_DataObject
     public $carrier;                         // int(4)
     public $smsnotify;                       // tinyint(1)
     public $smsreplies;                      // tinyint(1)
-    public $smsemail;                        // varchar(255)
-    public $uri;                             // varchar(255)  unique_key
+    public $smsemail;                        // varchar(191)               not 255 because utf8mb4 takes more space
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $autosubscribe;                   // tinyint(1)
     public $subscribe_policy;                // tinyint(1)
     public $urlshorteningservice;            // varchar(50)   default_ur1.ca
@@ -69,9 +69,9 @@ class User extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
                 'nickname' => array('type' => 'varchar', 'length' => 64, 'description' => 'nickname or username, duped in profile'),
-                'password' => array('type' => 'varchar', 'length' => 255, 'description' => 'salted password, can be null for OpenID users'),
-                'email' => array('type' => 'varchar', 'length' => 255, 'description' => 'email address for password recovery etc.'),
-                'incomingemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'email address for post-by-email'),
+                'password' => array('type' => 'varchar', 'length' => 191, 'description' => 'salted password, can be null for OpenID users'),
+                'email' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for password recovery etc.'),
+                'incomingemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for post-by-email'),
                 'emailnotifysub' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of subscriptions'),
                 'emailnotifyfav' => array('type' => 'int', 'size' => 'tiny', 'default' => null, 'description' => 'Notify by email of favorites'),
                 'emailnotifynudge' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of nudges'),
@@ -85,8 +85,8 @@ class User extends Managed_DataObject
                 'carrier' => array('type' => 'int', 'description' => 'foreign key to sms_carrier'),
                 'smsnotify' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS'),
                 'smsreplies' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS on replies'),
-                'smsemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'built from sms and carrier'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+                'smsemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'built from sms and carrier'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
                 'autosubscribe' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'automatically subscribe to users who subscribe to us'),
                 'subscribe_policy' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => '0 = anybody can subscribe; 1 = require approval'),
                 'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
@@ -687,11 +687,9 @@ class User extends Managed_DataObject
         return $stream->getNotices($offset, $limit, $since_id, $max_id);
     }
 
-
-    function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
+    public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
     {
-        // TRANS: Exception thrown when trying view "repeated to me".
-        throw new Exception(_('Not implemented since inbox change.'));
+        return $this->getProfile()->repeatedToMe($offset, $limit, $since_id, $max_id);
     }
 
     public static function siteOwner()
@@ -994,6 +992,11 @@ class User extends Managed_DataObject
         return $act;
     }
 
+    public function isPrivateStream()
+    {
+        return $this->getProfile()->isPrivateStream();
+    }
+
     public function delPref($namespace, $topic)
     {
         return $this->getProfile()->delPref($namespace, $topic);
index 875f5d650e9ca5d036217e36896f5933e2b7d961..3dc5fd4b2d8e0e1e799fad943b59301621a05ee3 100644 (file)
@@ -15,18 +15,18 @@ class User_group extends Managed_DataObject
     public $__table = 'user_group';                      // table name
     public $id;                              // int(4)  primary_key not_null
     public $nickname;                        // varchar(64)
-    public $fullname;                        // varchar(255)
-    public $homepage;                        // varchar(255)
+    public $fullname;                        // varchar(191)   not 255 because utf8mb4 takes more space
+    public $homepage;                        // varchar(191)   not 255 because utf8mb4 takes more space
     public $description;                     // text
-    public $location;                        // varchar(255)
-    public $original_logo;                   // varchar(255)
-    public $homepage_logo;                   // varchar(255)
-    public $stream_logo;                     // varchar(255)
-    public $mini_logo;                       // varchar(255)
+    public $location;                        // varchar(191)   not 255 because utf8mb4 takes more space
+    public $original_logo;                   // varchar(191)   not 255 because utf8mb4 takes more space
+    public $homepage_logo;                   // varchar(191)   not 255 because utf8mb4 takes more space
+    public $stream_logo;                     // varchar(191)   not 255 because utf8mb4 takes more space
+    public $mini_logo;                       // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime   not_null default_0000-00-00%2000%3A00%3A00
     public $modified;                        // timestamp   not_null default_CURRENT_TIMESTAMP
-    public $uri;                             // varchar(255)  unique_key
-    public $mainpage;                        // varchar(255)
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
+    public $mainpage;                        // varchar(191)   not 255 because utf8mb4 takes more space
     public $join_policy;                     // tinyint
     public $force_scope;                     // tinyint
 
@@ -41,21 +41,21 @@ class User_group extends Managed_DataObject
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
 
                 'nickname' => array('type' => 'varchar', 'length' => 64, 'description' => 'nickname for addressing'),
-                'fullname' => array('type' => 'varchar', 'length' => 255, 'description' => 'display name'),
-                'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL, cached so we dont regenerate'),
+                'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name'),
+                'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
                 'description' => array('type' => 'text', 'description' => 'group description'),
-                'location' => array('type' => 'varchar', 'length' => 255, 'description' => 'related physical location, if any'),
+                'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'related physical location, if any'),
 
-                'original_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'original size logo'),
-                'homepage_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'homepage (profile) size logo'),
-                'stream_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'stream-sized logo'),
-                'mini_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'mini logo'),
+                'original_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'original size logo'),
+                'homepage_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'homepage (profile) size logo'),
+                'stream_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'stream-sized logo'),
+                'mini_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'mini logo'),
 
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
 
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
-                'mainpage' => array('type' => 'varchar', 'length' => 255, 'description' => 'page for group info to link to'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
+                'mainpage' => array('type' => 'varchar', 'length' => 191, 'description' => 'page for group info to link to'),
                 'join_policy' => array('type' => 'int', 'size' => 'tiny', 'description' => '0=open; 1=requires admin approval'),      
                 'force_scope' => array('type' => 'int', 'size' => 'tiny', 'description' => '0=never,1=sometimes,-1=always'),
             ),
index cba91ea252cc41a28ff27f42eccb4003af01ce50..16fd030bb42ce43c35307ef4d8826fb3fa5fd263 100644 (file)
@@ -36,8 +36,8 @@ class User_im_prefs extends Managed_DataObject
 
     public $__table = 'user_im_prefs';       // table name
     public $user_id;                         // int(4)  primary_key not_null
-    public $screenname;                      // varchar(255)  not_null
-    public $transport;                       // varchar(255)  not_null
+    public $screenname;                      // varchar(191)  not_null   not 255 because utf8mb4 takes more space
+    public $transport;                       // varchar(191)  not_null   not 255 because utf8mb4 takes more space
     public $notify;                          // tinyint(1)
     public $replies;                         // tinyint(1)
     public $microid;                         // tinyint(1)
@@ -53,8 +53,8 @@ class User_im_prefs extends Managed_DataObject
         return array(
             'fields' => array(
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user'),
-                'screenname' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'screenname on this service'),
-                'transport' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'),
+                'screenname' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'screenname on this service'),
+                'transport' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'),
                 'notify' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Notify when a new notice is sent'),
                 'replies' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Send replies  from people not subscribed to'),
                 'microid' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'Publish a MicroID'),
index b252ee31565f58234859ca87ac1eaa23bdd7123e..0173a6efc4a0d647c76122014841363d2ce47946 100644 (file)
@@ -11,8 +11,8 @@ class User_username extends Managed_DataObject
 
     public $__table = 'user_username';                     // table name
     public $user_id;                        // int(4)  not_null
-    public $provider_name;                  // varchar(255)  primary_key not_null
-    public $username;                       // varchar(255)  primary_key not_null
+    public $provider_name;                  // varchar(191)  primary_key not_null   not 255 because utf8mb4 takes more space
+    public $username;                       // varchar(191)  primary_key not_null   not 255 because utf8mb4 takes more space
     public $created;                        // datetime()   not_null
     public $modified;                       // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -23,8 +23,8 @@ class User_username extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'provider_name' => array('type' => 'varchar', 'length' => 255, 'description' => 'provider name'),
-                'username' => array('type' => 'varchar', 'length' => 255, 'description' => 'username'),
+                'provider_name' => array('type' => 'varchar', 'length' => 191, 'description' => 'provider name'),
+                'username' => array('type' => 'varchar', 'length' => 191, 'description' => 'username'),
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id this title relates to'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index c630a83d522cfdbf7c35f72adfb572d65b5b5bbb..5e9693f5f71ac5b7d0fa4dad3dd9db1905c707fe 100644 (file)
@@ -21,7 +21,7 @@ create table status_network (
     created datetime not null comment 'date this record was created',
     modified timestamp comment 'date this record was modified'
 
-) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
 
 create table status_network_tag (
     site_id integer  comment 'unique id',
@@ -30,5 +30,5 @@ create table status_network_tag (
 
     constraint primary key (site_id, tag),
     index status_network_tag_tag_idx (tag)
-) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
 
index d72cf69b07b68dd1429755a73ad6fff4ee2b2d25..2752c967677cddc4dc07e68d43537893fbe4413e 100644 (file)
@@ -265,10 +265,10 @@ class WebInstaller extends Installer
                     <li>
                         <label for="site_profile">Type of site</label>
                         <select id="site_profile" name="site_profile">
-                            <option value="private">Private</option>
                             <option value="community">Community</option>
-                            <option value ="public">Public</option>
-                            <option value ="singleuser">Single User</option>
+                            <option value="public">Public (open registration)</option>
+                            <option value="singleuser">Single User</option>
+                            <option value="private">Private (no federation)</option>
                         </select>
                         <p class="form_guide">Initial access settings for your site</p>
                     </li>
index 6a1eb82b2e04139b6aed977a773be0cdb1cf4f2b..2611d8515ac73e6b8b1812d68696b2075cf874a0 100644 (file)
@@ -1562,60 +1562,6 @@ var SN = { // StatusNet
             });
         },
 
-        /**
-         * Called when a people tag edit box is shown in the interface
-         *
-         * - loads the jQuery UI autocomplete plugin
-         * - sets event handlers for tag completion
-         *
-         */
-        PeopletagAutocomplete: function (txtBox) {
-            var split = function (val) {
-                return val.split( /\s+/ );
-            }
-            var extractLast = function (term) {
-                return split(term).pop();
-            }
-
-            // don't navigate away from the field on tab when selecting an item
-            txtBox.on( "keydown", function ( event ) {
-                if ( event.keyCode === $.ui.keyCode.TAB &&
-                        $(this).data( "ui-autocomplete" ).menu.active ) {
-                    event.preventDefault();
-                }
-            }).autocomplete({
-                minLength: 0,
-                source: function (request, response) {
-                    // delegate back to autocomplete, but extract the last term
-                    response($.ui.autocomplete.filter(
-                        SN.C.PtagACData, extractLast(request.term)));
-                },
-                focus: function () {
-                    return false;
-                },
-                select: function (event, ui) {
-                    var terms = split(this.value);
-                    terms.pop();
-                    terms.push(ui.item.value);
-                    terms.push("");
-                    this.value = terms.join(" ");
-                    return false;
-                }
-            }).data('ui-autocomplete')._renderItem = function (ul, item) {
-                    // FIXME: with jQuery UI you cannot have it highlight the match
-                    var _l = '<a class="ptag-ac-line-tag">' + item.tag
-                          + ' <em class="privacy_mode">' + item.mode + '</em>'
-                          + '<span class="freq">' + item.freq + '</span></a>'
-
-                    return $("<li/>")
-                            .addClass('mode-' + item.mode)
-                            .addClass('ptag-ac-line')
-                            .data("item.autocomplete", item)
-                            .append(_l)
-                            .appendTo(ul);
-                }
-        },
-
         /**
          * Run setup for the ajax people tags editor
          *
@@ -1644,7 +1590,6 @@ var SN = { // StatusNet
                         }
 
                         SN.C.PtagACData = data;
-                        SN.Init.PeopletagAutocomplete(form.find('#tags'));
                     }
                 });
 
index 4e13419ae7482ccd0aed3eac7ffad9e15e6ca789..5bef4cfb072475e66cdaf73d1b4b4267107f78ed 100644 (file)
@@ -213,7 +213,7 @@ class ActivityImporter extends QueueHandler
 
         // Get (safe!) HTML and text versions of the content
 
-        $rendered = $this->purify($sourceContent);
+        $rendered = common_purify($sourceContent);
         $content = common_strip_html($rendered);
 
         $shortened = $user->shortenLinks($content);
@@ -338,15 +338,4 @@ class ActivityImporter extends QueueHandler
 
         return array($groups, $replies);
     }
-
-
-    function purify($content)
-    {
-        require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
-        $config = array('safe' => 1,
-                        'deny_attribute' => 'id,style,on*');
-
-        return htmLawed($content, $config);
-    }
 }
index 5cebce33da178c753cc2bf4776eb9b9e742da730..f1304a1d1e4f40d7f28db1c480de4706628504df 100755 (executable)
@@ -264,22 +264,20 @@ class ApiAction extends Action
         $twitter_user['statuses_count'] = $profile->noticeCount();
 
         // Is the requesting user following this user?
+        // These values might actually also mean "unknown". Ambiguity issues?
         $twitter_user['following'] = false;
         $twitter_user['statusnet_blocking'] = false;
         $twitter_user['notifications'] = false;
 
-        if (isset($this->auth_user)) {
-
-            $twitter_user['following'] = $this->auth_user->isSubscribed($profile);
-            $twitter_user['statusnet_blocking']  = $this->auth_user->hasBlocked($profile);
-
-            // Notifications on?
-            $sub = Subscription::pkeyGet(array('subscriber' =>
-                                               $this->auth_user->id,
-                                               'subscribed' => $profile->id));
-
-            if ($sub) {
+        if ($this->scoped instanceof Profile) {
+            try {
+                $sub = Subscription::getSubscription($this->scoped, $profile);
+                // Notifications on?
+                $twitter_user['following'] = true;
+                $twitter_user['statusnet_blocking']  = $this->scoped->hasBlocked($profile);
                 $twitter_user['notifications'] = ($sub->jabber || $sub->sms);
+            } catch (NoResultException $e) {
+                // well, the values are already false...
             }
         }
 
@@ -430,11 +428,11 @@ class ApiAction extends Action
         $twitter_group['nickname'] = $group->nickname;
         $twitter_group['fullname'] = $group->fullname;
 
-        if (isset($this->auth_user)) {
-            $twitter_group['member'] = $this->auth_user->isMember($group);
+        if ($this->scoped instanceof Profile) {
+            $twitter_group['member'] = $this->scoped->isMember($group);
             $twitter_group['blocked'] = Group_block::isBlocked(
                 $group,
-                $this->auth_user->getProfile()
+                $this->scoped
             );
         }
 
@@ -485,8 +483,8 @@ class ApiAction extends Action
         $twitter_list['member_count'] = $list->taggedCount();
         $twitter_list['uri'] = $list->getUri();
 
-        if (isset($this->auth_user)) {
-            $twitter_list['following'] = $list->hasSubscriber($this->auth_user);
+        if ($this->scoped instanceof Profile) {
+            $twitter_list['following'] = $list->hasSubscriber($this->scoped);
         } else {
             $twitter_list['following'] = false;
         }
@@ -575,37 +573,30 @@ class ApiAction extends Action
         $relationship = array();
 
         $relationship['source'] =
-            $this->relationshipDetailsArray($source, $target);
+            $this->relationshipDetailsArray($source->getProfile(), $target->getProfile());
         $relationship['target'] =
-            $this->relationshipDetailsArray($target, $source);
+            $this->relationshipDetailsArray($target->getProfile(), $source->getProfile());
 
         return array('relationship' => $relationship);
     }
 
-    function relationshipDetailsArray($source, $target)
+    function relationshipDetailsArray(Profile $source, Profile $target)
     {
         $details = array();
 
-               $source_profile = $source->getProfile();
-               $target_profile = $target->getProfile();                
-
-        $details['screen_name'] = $source->nickname;
-        $details['followed_by'] = $target->isSubscribed($source_profile);
-        $details['following'] = $source->isSubscribed($target_profile);
+        $details['screen_name'] = $source->getNickname();
+        $details['followed_by'] = $target->isSubscribed($source);
 
-        $notifications = false;
-
-        if ($source->isSubscribed($target_profile)) {
-            $sub = Subscription::pkeyGet(array('subscriber' =>
-                $source->id, 'subscribed' => $target->id));
-
-            if (!empty($sub)) {
-                $notifications = ($sub->jabber || $sub->sms);
-            }
+        try {
+            $sub = Subscription::getSubscription($source, $target);
+            $details['following'] = true;
+            $details['notifications_enabled'] = ($sub->jabber || $sub->sms);
+        } catch (NoResultException $e) {
+            $details['following'] = false;
+            $details['notifications_enabled'] = false;
         }
 
-        $details['notifications_enabled'] = $notifications;
-        $details['blocking'] = $source->hasBlocked($target_profile);
+        $details['blocking'] = $source->hasBlocked($target);
         $details['id'] = intval($source->id);
 
         return $details;
@@ -788,7 +779,7 @@ class ApiAction extends Action
     function showSingleAtomStatus($notice)
     {
         header('Content-Type: application/atom+xml; charset=utf-8');
-        print $notice->asAtomEntry(true, true, true, $this->auth_user);
+        print $notice->asAtomEntry(true, true, true, $this->scoped);
     }
 
     function show_single_json_status($notice)
@@ -1352,7 +1343,7 @@ class ApiAction extends Action
                 return User::getKV('nickname', $nickname);
             } else {
                 // Fall back to trying the currently authenticated user
-                return $this->auth_user;
+                return $this->scoped->getUser();
             }
 
         } else if (self::is_decimal($id)) {
@@ -1448,7 +1439,7 @@ class ApiAction extends Action
             }
 
             if (!empty($list) && $list->private) {
-                if ($this->auth_user->id == $list->tagger) {
+                if ($this->scoped->id == $list->tagger) {
                     return $list;
                 }
             } else {
index 6ca61f191b2c6160802434bb60e4351ac78204dc..0e6ad7b9fd53bd94adaef93a3b90e87107068e9e 100644 (file)
@@ -53,7 +53,7 @@ $default =
               'broughtbyurl' => null,
               'closed' => false,
               'inviteonly' => true,
-              'private' => true,
+              'private' => false,
               'ssl' => 'never',
               'sslserver' => null,
               'dupelimit' => 60, // default for same person saying the same thing
@@ -207,6 +207,9 @@ $default =
         'newuser' =>
         array('default' => null,
               'welcome' => null),
+        'linkify' => array(
+            'bare_domains' => false,  // convert domain.com to <a href="http://domain.com/" ...>domain.com</a> ?
+        ),
         'attachments' =>
         array('server' => null,
               'dir' => INSTALLDIR . '/file/',
@@ -250,6 +253,7 @@ $default =
               'user_quota' => 50000000,
               'monthly_quota' => 15000000,
               'uploads' => true,
+              'filename_base' => 'hash',   // for new files, choose one: 'upload', 'hash'
               'show_html' => false,  // show (filtered) text/html attachments (and oEmbed HTML etc.). Doesn't affect AJAX calls.
               'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
               'process_links' => true, // check linked resources for embeddable photos and videos; this will hit referenced external web sites when processing new messages.
index aa52fa361ca570f5605690fdbd0a3712387a719c..e6bb41091e1d6f9f104c0b5f50adfb94b1c0092c 100644 (file)
@@ -139,6 +139,11 @@ class Event {
         return false;
     }
 
+    public static function getHandlers($name)
+    {
+        return Event::$_handlers[$name];
+    }
+
     /**
      * Disables any and all handlers that have been set up so far;
      * use only if you know it's safe to reinitialize all plugins.
index 2dc260b1bf8cad511abe131d254ab4648db659d8..4ea1803f39ae812a5e491144a8c6cd45e58f4734 100644 (file)
@@ -53,8 +53,9 @@ class ImageFile
     var $width;
     var $rotate=0;  // degrees to rotate for properly oriented image (extrapolated from EXIF etc.)
     var $animated = null;  // Animated image? (has more than 1 frame). null means untested
+    var $mimetype = null;   // The _ImageFile_ mimetype, _not_ the originating File object
 
-    function __construct($id=null, $filepath=null, $type=null, $width=null, $height=null)
+    function __construct($id, $filepath)
     {
         $this->id = $id;
         $this->filepath = $filepath;
@@ -74,9 +75,10 @@ class ImageFile
             throw new UnsupportedMediaException(_('Unsupported image format.'), $this->filepath);
         }
 
-        $this->type = ($info) ? $info[2]:$type;
-        $this->width = ($info) ? $info[0]:$width;
-        $this->height = ($info) ? $info[1]:$height;
+        $this->width    = $info[0];
+        $this->height   = $info[1];
+        $this->type     = $info[2];
+        $this->mimetype = $info['mime'];
 
         if ($this->type == IMAGETYPE_JPEG && function_exists('exif_read_data')) {
             // Orientation value to rotate thumbnails properly
@@ -141,7 +143,7 @@ class ImageFile
     public function getPath()
     {
         if (!file_exists($this->filepath)) {
-            throw new ServerException('No file in ImageFile filepath');
+            throw new FileNotFoundException($this->filepath);
         }
 
         return $this->filepath;
index cea7d29ec7df621801ffaeb934fc5fd7462b65ed..1fcd0961c5ba9c9b365797caada18e241f496a01 100644 (file)
@@ -101,7 +101,7 @@ abstract class Installer
             $pass = false;
         }
 
-        $reqs = array('gd', 'curl', 'json',
+        $reqs = array('gd', 'curl', 'intl', 'json',
                       'xmlwriter', 'mbstring', 'xml', 'dom', 'simplexml');
 
         foreach ($reqs as $req) {
index 3bbbd162f0c18985d7cfc6238ab2b2d39854d8a5..bcc8662f56f6e632895806794b6fcdacc7f387cf 100644 (file)
@@ -42,12 +42,13 @@ class MediaFile
     var $short_fileurl = null;
     var $mimetype      = null;
 
-    function __construct(Profile $scoped, $filename = null, $mimetype = null)
+    function __construct(Profile $scoped, $filename = null, $mimetype = null, $filehash = null)
     {
         $this->scoped = $scoped;
 
         $this->filename   = $filename;
         $this->mimetype   = $mimetype;
+        $this->filehash   = $filehash;
         $this->fileRecord = $this->storeFile();
 
         $this->fileurl = common_local_url('attachment',
@@ -90,16 +91,40 @@ class MediaFile
 
     protected function storeFile()
     {
+        $filepath       = File::path($this->filename);
+        if (!empty($this->filename) && $this->filehash === null) {
+            // Calculate if we have an older upload method somewhere (Qvitter) that
+            // doesn't do this before calling new MediaFile on its local files...
+            $this->filehash = hash_file(File::FILEHASH_ALG, $filepath);
+            if ($this->filehash === false) {
+                throw new ServerException('Could not read file for hashing');
+            }
+        }
+
+        try {
+            $file = File::getByHash($this->filehash);
+            // We're done here. Yes. Already. We assume sha256 won't collide on us anytime soon.
+            return $file;
+        } catch (NoResultException $e) {
+            // Well, let's just continue below.
+        }
+
+        $fileurl = File::url($this->filename);
 
         $file = new File;
 
         $file->filename = $this->filename;
-        $file->url      = File::url($this->filename);
-        $filepath       = File::path($this->filename);
+        $file->urlhash  = File::hashurl($fileurl);
+        $file->url      = $fileurl;
+        $file->filehash = $this->filehash;
         $file->size     = filesize($filepath);
+        if ($file->size === false) {
+            throw new ServerException('Could not read file to get its size');
+        }
         $file->date     = time();
         $file->mimetype = $this->mimetype;
 
+
         $file_id = $file->insert();
 
         if ($file_id===false) {
@@ -139,10 +164,11 @@ class MediaFile
 
     function maybeAddRedir($file_id, $url)
     {
-        $file_redir = File_redirection::getKV('url', $url);
-
-        if (!$file_redir instanceof File_redirection) {
+        try {
+            $file_redir = File_redirection::getByUrl($url);
+        } catch (NoResultException $e) {
             $file_redir = new File_redirection;
+            $file_redir->urlhash = File::hashurl($url);
             $file_redir->url = $url;
             $file_redir->file_id = $file_id;
 
@@ -203,49 +229,86 @@ class MediaFile
                 throw new ClientException(_('System error uploading file.'));
         }
 
-        // Throws exception if additional size does not respect quota
-        File::respectsQuota($scoped, $_FILES[$param]['size']);
+        // TODO: Make documentation clearer that this won't work for files >2GiB because
+        //       PHP is stupid in its 32bit head. But noone accepts 2GiB files with PHP
+        //       anyway... I hope.
+        $filehash = hash_file(File::FILEHASH_ALG, $_FILES[$param]['tmp_name']);
 
-        $mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'],
-                $_FILES[$param]['name']);
+        try {
+            $file = File::getByHash($filehash);
+            // If no exception is thrown the file exists locally, so we'll use that and just add redirections.
+            $filename = $file->filename;
+            $mimetype = $file->mimetype;
+
+        } catch (NoResultException $e) {
+            // We have to save the upload as a new local file. This is the normal course of action.
 
-        $basename = basename($_FILES[$param]['name']);
-        $filename = File::filename($scoped, $basename, $mimetype);
-        $filepath = File::path($filename);
+            // Throws exception if additional size does not respect quota
+            // This test is only needed, of course, if we're uploading something new.
+            File::respectsQuota($scoped, $_FILES[$param]['size']);
 
-        $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath);
+            $mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'], $_FILES[$param]['name']);
 
-        if (!$result) {
-            // TRANS: Client exception thrown when a file upload operation fails because the file could
-            // TRANS: not be moved from the temporary folder to the permanent file location.
-            throw new ClientException(_('File could not be moved to destination directory.'));
+            switch (common_config('attachments', 'filename_base')) {
+            case 'upload':
+                $basename = basename($_FILES[$param]['name']);
+                $filename = File::filename($scoped, $basename, $mimetype);
+                break;
+            case 'hash':
+            default:
+                $filename = strtolower($filehash) . '.' . File::guessMimeExtension($mimetype); 
+            }
+            $filepath = File::path($filename);
+
+            $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath);
+
+            if (!$result) {
+                // TRANS: Client exception thrown when a file upload operation fails because the file could
+                // TRANS: not be moved from the temporary folder to the permanent file location.
+                throw new ClientException(_('File could not be moved to destination directory.'));
+            }
         }
 
-        return new MediaFile($scoped, $filename, $mimetype);
+        return new MediaFile($scoped, $filename, $mimetype, $filehash);
     }
 
     static function fromFilehandle($fh, Profile $scoped) {
-
         $stream = stream_get_meta_data($fh);
+        // So far we're only handling filehandles originating from tmpfile(),
+        // so we can always do hash_file on $stream['uri'] as far as I can tell!
+        $filehash = hash_file(File::FILEHASH_ALG, $stream['uri']);
 
-        File::respectsQuota($scoped, filesize($stream['uri']));
-
-        $mimetype = self::getUploadedMimeType($stream['uri']);
-
-        $filename = File::filename($scoped, "email", $mimetype);
-
-        $filepath = File::path($filename);
+        try {
+            $file = File::getByHash($filehash);
+            // Already have it, so let's reuse the locally stored File
+            $filename = $file->filename;
+            $mimetype = $file->mimetype;
+        } catch (NoResultException $e) {
+            File::respectsQuota($scoped, filesize($stream['uri']));
+
+            $mimetype = self::getUploadedMimeType($stream['uri']);
+
+            switch (common_config('attachments', 'filename_base')) {
+            case 'upload':
+                $filename = File::filename($scoped, "email", $mimetype);
+                break;
+            case 'hash':
+            default:
+                $filename = strtolower($filehash) . '.' . File::guessMimeExtension($mimetype);
+            }
+            $filepath = File::path($filename);
 
-        $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
+            $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
 
-        if (!$result) {
-            // TRANS: Client exception thrown when a file upload operation fails because the file could
-            // TRANS: not be moved from the temporary folder to the permanent file location.
-            throw new ClientException(_('File could not be moved to destination directory.' .
-                $stream['uri'] . ' ' . $filepath));
+            if (!$result) {
+                // TRANS: Client exception thrown when a file upload operation fails because the file could
+                // TRANS: not be moved from the temporary folder to the permanent file location.
+                throw new ClientException(_('File could not be moved to destination directory.' .
+                    $stream['uri'] . ' ' . $filepath));
+            }
         }
 
-        return new MediaFile($scoped, $filename, $mimetype);
+        return new MediaFile($scoped, $filename, $mimetype, $filehash);
     }
 
     /**
index 435ba4e3a95f57f3ca0ba314db4fb483d0ca0b83..f1fc0f46ecd5c600fa12c4d4e128387288718ac1 100644 (file)
@@ -271,7 +271,7 @@ class MysqlSchema extends Schema
     function endCreateTable($name, array $def)
     {
         $engine = $this->preferredEngine($def);
-        return ") ENGINE=$engine CHARACTER SET utf8 COLLATE utf8_bin";
+        return ") ENGINE=$engine CHARACTER SET utf8mb4 COLLATE utf8mb4_bin";
     }
     
     function preferredEngine($def)
@@ -335,9 +335,10 @@ class MysqlSchema extends Schema
         if (strtolower($oldProps['ENGINE']) != strtolower($engine)) {
             $phrase[] = "ENGINE=$engine";
         }
-        if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8_bin') {
-            $phrase[] = 'DEFAULT CHARSET=utf8';
-            $phrase[] = 'COLLATE=utf8_bin';
+        if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8mb4_bin') {
+            $phrase[] = 'CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin';
+            $phrase[] = 'DEFAULT CHARACTER SET = utf8mb4';
+            $phrase[] = 'DEFAULT COLLATE = utf8mb4_bin';
         }
     }
 
index 1960a0693001c6948191dcf629b71c1bab38945e..ae746c10b546a4919fde4ab68f63a6943c5194cc 100644 (file)
@@ -28,9 +28,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 class SchemaUpdater
 {
@@ -46,6 +44,11 @@ class SchemaUpdater
      */
     public function register($tableName, array $tableDef)
     {
+        // Check if the table we're registering is related to a Managed_DataObject
+        if (is_a(ucfirst($tableName), 'Managed_DataObject', true)) {
+            call_user_func("{$tableName}::beforeSchemaUpdate");
+        }
+
         $this->tables[$tableName] = $tableDef;
     }
 
index a32c35395eb91ba004f48d43b828110195d54159..9a70d8d44ebaf9f010675b0c88d5691b01258101 100644 (file)
@@ -576,6 +576,25 @@ function common_canonical_email($email)
     return $email;
 }
 
+function common_purify($html)
+{
+    require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
+
+    $config = array('safe' => 1,
+                    'deny_attribute' => 'id,style,on*');
+
+    $html = common_remove_unicode_formatting($html);
+
+    return htmLawed($html, $config);
+}
+
+function common_remove_unicode_formatting($text)
+{
+    // Strip Unicode text formatting/direction codes
+    // this is pretty dangerous for visualisation of text and can be used for mischief
+    return preg_replace('/[\\x{200b}-\\x{200f}\\x{202a}-\\x{202e}]/u', '', $text);
+}
+
 /**
  * Partial notice markup rendering step: build links to !group references.
  *
@@ -585,9 +604,9 @@ function common_canonical_email($email)
  */
 function common_render_content($text, Notice $notice)
 {
-    $r = common_render_text($text);
-    $r = common_linkify_mentions($r, $notice);
-    return $r;
+    $text = common_render_text($text);
+    $text = common_linkify_mentions($text, $notice);
+    return $text;
 }
 
 /**
@@ -829,14 +848,15 @@ function common_find_mentions_raw($text)
 
 function common_render_text($text)
 {
-    $r = nl2br(htmlspecialchars($text));
+    $text = common_remove_unicode_formatting($text);
+    $text = nl2br(htmlspecialchars($text));
 
-    $r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r);
-    $r = common_replace_urls_callback($r, 'common_linkify');
-    $r = preg_replace_callback('/(^|\&quot\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/u',
-                function ($m) { return "{$m[1]}#".common_tag_link($m[2]); }, $r);
+    $text = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $text);
+    $text = common_replace_urls_callback($text, 'common_linkify');
+    $text = preg_replace_callback('/(^|\&quot\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/u',
+                function ($m) { return "{$m[1]}#".common_tag_link($m[2]); }, $text);
     // XXX: machine tags
-    return $r;
+    return $text;
 }
 
 /**
@@ -870,12 +890,15 @@ function common_replace_urls_callback($text, $callback, $arg = null) {
             '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4
             '|(?:'. //IPv6
                 '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)'.
-            ')|(?:'. //DNS
-                '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
-                '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
-                //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
-                '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZONE|ZW|local|loc|onion)'.
-            ')(?![\pN\pL\-\_])'.
+            ')'.
+            (common_config('linkify', 'bare_domains')
+                ? '|(?:'. //DNS
+                    '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
+                    '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
+                    //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
+                    '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZONE|ZW|local|loc|onion)'.
+            ')(?![\pN\pL\-\_])'
+                : '') . // if common_config('linkify', 'bare_domains') is false, don't add anything here
         ')'.
         '(?:'.
             '(?:\:\d+)?'. //:port
@@ -1116,6 +1139,20 @@ function common_xml_safe_str($str)
     return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
 }
 
+function common_slugify($str)
+{
+    $str = transliterator_transliterate(
+                        'Any-Latin;' .      // any charset to latin compatible
+                            'NFD;' .        // decompose
+                            '[:Nonspacing Mark:] Remove;' . // remove nonspacing marks (accents etc.)
+                            'NFC;' .        // composite again
+                            '[:Punctuation:] Remove;' . // remove punctuation (.,¿? etc.)
+                            'Lower();' .    // turn into lowercase
+                            'Latin-ASCII;',  // get ASCII equivalents (ð to d for example)
+                        $str);
+    return preg_replace('/[^\pL\pN]/', '', $str);
+}
+
 function common_tag_link($tag)
 {
     $canonical = common_canonical_tag($tag);
@@ -1139,11 +1176,9 @@ function common_tag_link($tag)
 
 function common_canonical_tag($tag)
 {
-  // only alphanum
-  $tag = preg_replace('/[^\pL\pN]/u', '', $tag);
-  $tag = mb_convert_case($tag, MB_CASE_LOWER, "UTF-8");
-  $tag = substr($tag, 0, 64);
-  return $tag;
+    $tag = common_slugify($tag);
+    $tag = substr($tag, 0, 64);
+    return $tag;
 }
 
 function common_valid_profile_tag($str)
index 481b2dedcabc8b80c3185ea12a61d976d38c1b61..71d57e2d56647afad12e413dda029a912c6e19bc 100644 (file)
@@ -212,7 +212,7 @@ class XMLOutputter
     {
         static $empty_tag = array('base', 'meta', 'link', 'hr',
                                   'br', 'param', 'img', 'area',
-                                  'input', 'col');
+                                  'input', 'col', 'source');
         // XXX: check namespace
         if (in_array($tag, $empty_tag)) {
             $this->xw->endElement();
index 4e7058dd9dd17ef556528c585e12ed1df16e2af5..ed1ea4225d10865b14fb7001e1b0940e37b7b026 100644 (file)
@@ -13,7 +13,7 @@ SN.Init.NoticeFormSetup = function(form) {
 
     // Only attach to traditional-style forms
     var textarea = form.find('.notice_data-text:first');
-    if (textarea.length == 0) {
+    if (textarea.length === 0) {
         return;
     }
 
@@ -69,3 +69,69 @@ SN.Init.NoticeFormSetup = function(form) {
                 .appendTo(ul);
         };
 };
+
+/**
+ * Called when a people tag edit box is shown in the interface
+ *
+ * - loads the jQuery UI autocomplete plugin
+ * - sets event handlers for tag completion
+ *
+ */
+SN.Init.PeopletagAutocomplete = function(txtBox) {
+    var split,
+        extractLast;
+
+    split = function(val) {
+        return val.split( /\s+/ );
+    };
+
+     extractLast = function(term) {
+        return split(term).pop();
+    };
+
+    // don't navigate away from the field on tab when selecting an item
+    txtBox
+        .on('keydown', function(event) {
+            if (event.keyCode === $.ui.keyCode.TAB &&
+                    $(this).data('ui-autocomplete').menu.active) {
+                event.preventDefault();
+            }
+        })
+        .autocomplete({
+            minLength: 0,
+            source: function(request, response) {
+                // delegate back to autocomplete, but extract the last term
+                response($.ui.autocomplete.filter(
+                    SN.C.PtagACData, extractLast(request.term)));
+            },
+            focus: function () {
+                return false;
+            },
+            select: function(event, ui) {
+                var terms = split(this.value);
+                terms.pop();
+                terms.push(ui.item.value);
+                terms.push('');
+                this.value = terms.join(' ');
+                return false;
+            }
+        })
+        .data('ui-autocomplete')
+        ._renderItem = function (ul, item) {
+            // FIXME: with jQuery UI you cannot have it highlight the match
+            var _l = '<a class="ptag-ac-line-tag">' + item.tag +
+                     ' <em class="privacy_mode">' + item.mode + '</em>' +
+                     '<span class="freq">' + item.freq + '</span></a>';
+
+            return $('<li/>')
+                    .addClass('mode-' + item.mode)
+                    .addClass('ptag-ac-line')
+                    .data('item.autocomplete', item)
+                    .append(_l)
+                    .appendTo(ul);
+        };
+};
+
+$(document).on('click', '.peopletags_edit_button', function () {
+    SN.Init.PeopletagAutocomplete($(this).closest('dd').find('[name="tags"]'));
+});
index fb2712f5658189c7e25eaff70ed37bfaae0ab461..fe357941c03bcc4fe88a90a2cc550280ab15282f 100644 (file)
@@ -47,7 +47,7 @@ require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
 class Homepage_blacklist extends Managed_DataObject
 {
     public $__table = 'homepage_blacklist'; // table name
-    public $pattern;                        // varchar(255) pattern
+    public $pattern;                        // varchar(191) pattern   not 255 because utf8mb4 takes more space
     public $created;                        // datetime not_null
     public $modified;                       // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -55,7 +55,7 @@ class Homepage_blacklist extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
+                'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'blacklist pattern'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index f4f387a2e02e6524a46d96c77d83dd0937d1bae2..b045fd17cebfdd5c170e1fee326139fb15a35cbc 100644 (file)
@@ -47,7 +47,7 @@ require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
 class Nickname_blacklist extends Managed_DataObject
 {
     public $__table = 'nickname_blacklist'; // table name
-    public $pattern;                        // varchar(255) pattern
+    public $pattern;                        // varchar(191) pattern   not 255 because utf8mb4 takes more space
     public $created;                        // datetime not_null
     public $modified;                       // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -55,7 +55,7 @@ class Nickname_blacklist extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
+                'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'blacklist pattern'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index 1f585dce4ff854c15b5b1c5ac8d0f7cebbd89671..95c1f6956be5712ab163d02b550408605979a80e 100644 (file)
@@ -51,11 +51,11 @@ class Blog_entry extends Managed_DataObject
 
     public $id; // UUID
     public $profile_id; // int
-    public $title; // varchar(255)
+    public $title; // varchar(191)   not 255 because utf8mb4 takes more space
     public $summary; // text
     public $content; // text
-    public $uri; // text
-    public $url; // text
+    public $uri; // varchar(191)   not 255 because utf8mb4 takes more space
+    public $url; // varchar(191)   not 255 because utf8mb4 takes more space
     public $created; // datetime
     public $modified; // datetime
 
@@ -74,17 +74,17 @@ class Blog_entry extends Managed_DataObject
                                       'not null' => true,
                                       'description' => 'Author profile ID'),
                 'title' => array('type' => 'varchar',
-                                 'length' => 255,
+                                 'length' => 191,
                                  'description' => 'title of the entry'),
                 'summary' => array('type' => 'text',
                                    'description' => 'initial summary'),
                 'content' => array('type' => 'text',
                                    'description' => 'HTML content of the entry'),
                 'uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'description' => 'URI (probably http://) for this entry'),
                 'url' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'description' => 'URL (probably http://) for this entry'),
                 'created' => array('type' => 'datetime',
                                    'not null' => true,
@@ -117,10 +117,10 @@ class Blog_entry extends Managed_DataObject
         $be->id         = (string) new UUID();
         $be->profile_id = $profile->id;
         $be->title      = $title; // Note: not HTML-protected
-        $be->content    = self::purify($content);
+        $be->content    = common_purify($content);
 
         if (array_key_exists('summary', $options)) {
-            $be->summary = self::purify($options['summary']);
+            $be->summary = common_purify($options['summary']);
         } else {
             // Already purified
             $be->summary = self::summarize($be->content);
@@ -241,18 +241,4 @@ class Blog_entry extends Managed_DataObject
 
         return $obj;
     }
-
-    /**
-     * Clean up input HTML
-     */
-    static function purify($html)
-    {
-        require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
-        $config = array('safe' => 1,
-                        'deny_attribute' => 'id,style,on*');
-        $pure = htmLawed($html, $config);
-
-        return $pure;
-    }
 }
index a99df87ee3d7da8da3a2117839f9d4d3a96d7a58..ade6b4fa7bb6fe4018410388206061dba635d8a5 100644 (file)
@@ -47,10 +47,10 @@ class Bookmark extends Managed_DataObject
     public $__table = 'bookmark'; // table name
     public $id;          // char(36) primary_key not_null
     public $profile_id;  // int(4) not_null
-    public $url;         // varchar(255) not_null
-    public $title;       // varchar(255)
+    public $url;         // varchar(191) not_null   not 255 because utf8mb4 takes more space
+    public $title;       // varchar(191)   not 255 because utf8mb4 takes more space
+    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
     public $description; // text
-    public $uri;         // varchar(255)
     public $created;     // datetime
 
     public static function schemaDef()
@@ -62,12 +62,12 @@ class Bookmark extends Managed_DataObject
                             'not null' => true),
                 'profile_id' => array('type' => 'int', 'not null' => true),
                 'uri' => array('type' => 'varchar',
-                            'length' => 255,
+                            'length' => 191,
                             'not null' => true),
                 'url' => array('type' => 'varchar',
-                            'length' => 255,
+                            'length' => 191,
                             'not null' => true),
-                'title' => array('type' => 'varchar', 'length' => 255),
+                'title' => array('type' => 'varchar', 'length' => 191),
                 'description' => array('type' => 'text'),
                 'created' => array('type' => 'datetime', 'not null' => true),
             ),
index 3818a38f48ffcc6dfee7635036644866cf160685..5f8d27b4f1584fa86069382de1dbcd344ab4e09b 100644 (file)
@@ -13,12 +13,12 @@ class Message extends Managed_DataObject
 
     public $__table = 'message';                         // table name
     public $id;                              // int(4)  primary_key not_null
-    public $uri;                             // varchar(255)  unique_key
+    public $uri;                             // varchar(191)  unique_key   not 255 because utf8mb4 takes more space
     public $from_profile;                    // int(4)   not_null
     public $to_profile;                      // int(4)   not_null
     public $content;                         // text()
     public $rendered;                        // text()
-    public $url;                             // varchar(255)
+    public $url;                             // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
     public $source;                          // varchar(32)
@@ -31,12 +31,12 @@ class Message extends Managed_DataObject
         return array(
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'),
                 'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is from'),
                 'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is to'),
                 'content' => array('type' => 'text', 'description' => 'message content'),
                 'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
+                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
                 'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'),
index 5e532fc214202cd909717be1cae84d09aadde98b..32e5ce50b4cdeb483831da0d9c3b150f4d7cfad4 100644 (file)
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET'))
-{
-    exit(1);
-}
-
-require_once INSTALLDIR . '/lib/publicgroupnav.php';
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * Group directory
@@ -40,10 +35,11 @@ require_once INSTALLDIR . '/lib/publicgroupnav.php';
  * @category Directory
  * @package  StatusNet
  * @author   Zach Copley <zach@status.net>
+ * @author   Mikael Nordfeldth <mmn@hethane.se>
  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  * @link     http://status.net/
  */
-class GroupdirectoryAction extends Action
+class GroupdirectoryAction extends ManagedAction
 {
     /**
      * The page we're on
@@ -138,17 +134,8 @@ class GroupdirectoryAction extends Action
         return true;
     }
 
-    /**
-     * Take arguments for running
-     *
-     * @param array $args $_REQUEST args
-     *
-     * @return boolean success flag
-     */
-    function prepare($args)
+    protected function doPreparation()
     {
-        parent::prepare($args);
-
         $this->page    = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
         $this->filter  = $this->arg('filter', 'all');
         $this->reverse = $this->boolean('reverse');
@@ -156,23 +143,6 @@ class GroupdirectoryAction extends Action
         $this->sort    = $this->arg('sort', 'nickname');
 
         common_set_returnto($this->selfUrl());
-
-        return true;
-    }
-
-    /**
-     * Handle request
-     *
-     * Shows the page
-     *
-     * @param array $args $_REQUEST args; handled in prepare()
-     *
-     * @return void
-     */
-    function handle($args)
-    {
-        parent::handle($args);
-        $this->showPage();
     }
 
     /**
@@ -303,74 +273,61 @@ class GroupdirectoryAction extends Action
     {
         $group = new User_group();
 
-        $offset = ($this->page-1) * PROFILES_PER_PAGE;
-        $limit  = PROFILES_PER_PAGE + 1;
+        // Disable this to get global group searches
+        $group->joinAdd(array('id', 'local_group:group_id'));
 
-        if (isset($this->q)) {
+        $order = false;
 
-             $order = 'user_group.created ASC';
-
-             if ($this->sort == 'nickname') {
-                 if ($this->reverse) {
-                     $order = 'user_group.nickname DESC';
-                 } else {
-                     $order = 'user_group.nickname ASC';
-                 }
-             } else {
-                 if ($this->reverse) {
-                     $order = 'user_group.created DESC';
-                 }
-             }
-
-             $sql = <<< GROUP_QUERY_END
-SELECT user_group.*
-FROM user_group
-JOIN local_group ON user_group.id = local_group.group_id
-ORDER BY %s
-LIMIT %d, %d
-GROUP_QUERY_END;
-
-        $cnt = 0;
-        $group->query(sprintf($sql, $order, $limit, $offset));
-        $group->find();
+        if (!empty($this->q)) {
+            $wheres = array('nickname', 'fullname', 'homepage', 'description', 'location');
+            foreach ($wheres as $where) {
+                // Double % because of sprintf
+                $group->whereAdd(sprintf('LOWER(%1$s.%2$s) LIKE LOWER("%%%3$s%%")',
+                                        $group->escapedTableName(), $where,
+                                        $group->escape($this->q)),
+                                    'OR');
+            }
 
+            $order = sprintf('%1$s.%2$s %3$s',
+                            $group->escapedTableName(),
+                            $this->getSortKey('created'),
+                            $this->reverse ? 'DESC' : 'ASC');
         } else {
             // User is browsing via AlphaNav
-            $sort   = $this->getSortKey();
-
-            $sql = <<< GROUP_QUERY_END
-SELECT user_group.*
-FROM user_group
-JOIN local_group ON user_group.id = local_group.group_id
-GROUP_QUERY_END;
 
-            switch($this->filter)
-            {
+            switch($this->filter) {
             case 'all':
                 // NOOP
                 break;
             case '0-9':
-                $sql .=
-                    '  AND LEFT(user_group.nickname, 1) BETWEEN \'0\' AND \'9\'';
+                $group->whereAdd(sprintf('LEFT(%1$s.%2$s, 1) BETWEEN %3$s AND %4$s',
+                                        $group->escapedTableName(),
+                                        'nickname',
+                                        $group->_quote("0"),
+                                        $group->_quote("9")));
                 break;
             default:
-                $sql .= sprintf(
-                    ' AND LEFT(LOWER(user_group.nickname), 1) = \'%s\'',
-                    $this->filter
-                );
+                $group->whereAdd(sprintf('LEFT(LOWER(%1$s.%2$s), 1) = %3$s',
+                                            $group->escapedTableName(),
+                                            'nickname',
+                                            $group->_quote($this->filter)));
             }
 
-            $sql .= sprintf(
-                ' ORDER BY user_group.%s %s, user_group.nickname ASC LIMIT %d, %d',
-                $sort,
-                $this->reverse ? 'DESC' : 'ASC',
-                $offset,
-                $limit
-            );
-
-            $group->query($sql);
+            $order = sprintf('%1$s.%2$s %3$s, %1$s.%4$s ASC',
+                            $group->escapedTableName(),
+                            $this->getSortKey('nickname'),
+                            $this->reverse ? 'DESC' : 'ASC',
+                            'nickname');
         }
 
+        $offset = ($this->page-1) * PROFILES_PER_PAGE;
+        $limit  = PROFILES_PER_PAGE + 1;
+
+        $group->orderBy($order);
+        $group->limit($offset, $limit);
+
+        $group->find();
+
         return $group;
     }
 
@@ -379,17 +336,14 @@ GROUP_QUERY_END;
      *
      * @return string   a column name for sorting
      */
-    function getSortKey()
+    function getSortKey($def='created')
     {
         switch ($this->sort) {
         case 'nickname':
-            return $this->sort;
-            break;
         case 'created':
             return $this->sort;
-            break;
         default:
-            return 'nickname';
+            return $def;
         }
     }
 
index 77ffb5206b22ee24d33930cdd1050110e2ec43ed..f178408e8bf11596d067fb5501ad1ead7c843956 100644 (file)
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET'))
-{
-    exit(1);
-}
-
-require_once INSTALLDIR . '/lib/publicgroupnav.php';
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * User directory
@@ -43,7 +38,7 @@ require_once INSTALLDIR . '/lib/publicgroupnav.php';
  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  * @link     http://status.net/
  */
-class UserdirectoryAction extends Action
+class UserdirectoryAction extends ManagedAction
 {
     /**
      * The page we're on
@@ -137,17 +132,8 @@ class UserdirectoryAction extends Action
         return true;
     }
 
-    /**
-     * Take arguments for running
-     *
-     * @param array $args $_REQUEST args
-     *
-     * @return boolean success flag
-     */
-    function prepare($args)
+    protected function doPreparation()
     {
-        parent::prepare($args);
-
         $this->page    = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
         $this->filter  = $this->arg('filter', 'all');
         $this->reverse = $this->boolean('reverse');
@@ -155,23 +141,6 @@ class UserdirectoryAction extends Action
         $this->sort    = $this->arg('sort', 'nickname');
 
         common_set_returnto($this->selfUrl());
-
-        return true;
-    }
-
-    /**
-     * Handle request
-     *
-     * Shows the page
-     *
-     * @param array $args $_REQUEST args; handled in prepare()
-     *
-     * @return void
-     */
-    function handle($args)
-    {
-        parent::handle($args);
-        $this->showPage();
     }
 
     /**
@@ -291,10 +260,13 @@ class UserdirectoryAction extends Action
     {
         $profile = new Profile();
 
+        // Comment this out or disable to get global profile searches
+        $profile->joinAdd(array('id', 'user:id'));
+
         $offset = ($this->page - 1) * PROFILES_PER_PAGE;
         $limit  = PROFILES_PER_PAGE + 1;
 
-        if (isset($this->q)) {
+        if (!empty($this->q)) {
              // User is searching via query
              $search_engine = $profile->getSearchEngine('profile');
 
@@ -319,34 +291,34 @@ class UserdirectoryAction extends Action
              $profile->find();
         } else {
             // User is browsing via AlphaNav
-            $sort   = $this->getSortKey();
-            $sql    = 'SELECT profile.* FROM profile, user WHERE profile.id = user.id';
 
-            switch($this->filter)
-            {
+            switch ($this->filter) {
             case 'all':
                 // NOOP
                 break;
             case '0-9':
-                $sql .=
-                    '  AND LEFT(profile.nickname, 1) BETWEEN \'0\' AND \'9\'';
+                $profile->whereAdd(sprintf('LEFT(%1$s.%2$s, 1) BETWEEN %3$s AND %4$s',
+                                            $profile->escapedTableName(),
+                                            'nickname',
+                                            $profile->_quote("0"),
+                                            $profile->_quote("9")));
                 break;
             default:
-                $sql .= sprintf(
-                    ' AND LEFT(LOWER(profile.nickname), 1) = \'%s\'',
-                    $this->filter
-                );
+                $profile->whereAdd(sprintf('LEFT(LOWER(%1$s.%2$s), 1) = %3$s',
+                                            $profile->escapedTableName(),
+                                            'nickname',
+                                            $profile->_quote($this->filter)));
             }
 
-            $sql .= sprintf(
-                ' ORDER BY profile.%s %s, profile.nickname ASC LIMIT %d, %d',
-                $sort,
-                $this->reverse ? 'DESC' : 'ASC',
-                $offset,
-                $limit
-            );
+            $order = sprintf('%1$s.%2$s %3$s, %1$s.%4$s ASC',
+                            $profile->escapedTableName(),
+                            $this->getSortKey('nickname'),
+                            $this->reverse ? 'DESC' : 'ASC',
+                            'nickname');
+            $profile->orderBy($order);
+            $profile->limit($offset, $limit);
 
-            $profile->query($sql);
+            $profile->find();
         }
 
         return $profile;
@@ -357,15 +329,12 @@ class UserdirectoryAction extends Action
      *
      * @return string   a column name for sorting
      */
-    function getSortKey()
+    function getSortKey($def='nickname')
     {
         switch ($this->sort) {
         case 'nickname':
-            return $this->sort;
-            break;
         case 'created':
             return $this->sort;
-            break;
         default:
             return 'nickname';
         }
index 235305f04722a3c26587edfa9a2287012879b9dc..7af2cdf5e6ac776f49d43b37e225d80d83798c98 100644 (file)
@@ -30,8 +30,8 @@ class Email_reminder extends Managed_DataObject
 {
     public $__table = 'email_reminder';
 
-    public $type;     // type of reminder
-    public $code;     // confirmation code
+    public $type;     // type of reminder varchar(191)    not 255 because utf8mb4 takes more space
+    public $code;     // confirmation code varchar(191)   not 255 because utf8mb4 takes more space
     public $days;     // number of days after code was created
     public $sent;     // timestamp
     public $created;  // timestamp
@@ -102,14 +102,14 @@ class Email_reminder extends Managed_DataObject
             'fields'      => array(
                 'type'     => array(
                     'type'          => 'varchar',
-                    'length'        => 255,
+                    'length'        => 191,
                     'not null'      => true,
                     'description'   => 'type of reminder'
                 ),
                 'code' => array(
                     'type'        => 'varchar',
                     'not null'    => 'true',
-                    'length'      => 255,
+                    'length'      => 191,
                     'description' => 'confirmation code'
                  ),
                 'days' => array(
index 3a094ece6cf3fe34672784e60544d3872b8a28d8..733235655c28c9faca4f72fe5d6ce138e70f2bd4 100644 (file)
@@ -53,13 +53,13 @@ class Happening extends Managed_DataObject
 
     public $__table = 'happening'; // table name
     public $id;                    // varchar(36) UUID
-    public $uri;                   // varchar(255)
+    public $uri;                   // varchar(191)   not 255 because utf8mb4 takes more space
     public $profile_id;            // int
     public $start_time;            // datetime
     public $end_time;              // datetime
-    public $title;                 // varchar(255)
-    public $location;              // varchar(255)
-    public $url;                   // varchar(255)
+    public $title;                 // varchar(191)   not 255 because utf8mb4 takes more space
+    public $location;              // varchar(191)   not 255 because utf8mb4 takes more space
+    public $url;                   // varchar(191)   not 255 because utf8mb4 takes more space
     public $description;           // text
     public $created;               // datetime
 
@@ -76,18 +76,18 @@ class Happening extends Managed_DataObject
                               'not null' => true,
                               'description' => 'UUID'),
                 'uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'profile_id' => array('type' => 'int', 'not null' => true),
                 'start_time' => array('type' => 'datetime', 'not null' => true),
                 'end_time' => array('type' => 'datetime', 'not null' => true),
                 'title' => array('type' => 'varchar',
-                                 'length' => 255,
+                                 'length' => 191,
                                  'not null' => true),
                 'location' => array('type' => 'varchar',
-                                    'length' => 255),
+                                    'length' => 191),
                 'url' => array('type' => 'varchar',
-                               'length' => 255),
+                               'length' => 191),
                 'description' => array('type' => 'text'),
                 'created' => array('type' => 'datetime',
                                    'not null' => true),
index 7266ea7493aa0ba7a508a8a78ca0e358750aefb0..3e0efc689a6a5dcbab2c9ccf14bf70b31d12fedb 100644 (file)
@@ -50,7 +50,7 @@ class RSVP extends Managed_DataObject
 
     public $__table = 'rsvp'; // table name
     public $id;                // varchar(36) UUID
-    public $uri;               // varchar(255)
+    public $uri;               // varchar(191)   not 255 because utf8mb4 takes more space
     public $profile_id;        // int
     public $event_id;          // varchar(36) UUID
     public $response;            // tinyint
@@ -83,7 +83,7 @@ class RSVP extends Managed_DataObject
                               'not null' => true,
                               'description' => 'UUID'),
                 'uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'profile_id' => array('type' => 'int'),
                 'event_id' => array('type' => 'char',
index a7cf5a13aa20cac519fe61fd462c6b0d565c9752..1f77bb1b4f117e9b4244ab55827b67a419f5f954 100644 (file)
@@ -52,7 +52,7 @@ class Notice_to_item extends Managed_DataObject
 {
     public $__table = 'notice_to_item'; // table name
     public $notice_id;                  // int(4)  primary_key not_null
-    public $item_id;                    // varchar(255) not null
+    public $item_id;                    // varchar(191) not null   not 255 because utf8mb4 takes more space
     public $created;                    // datetime
 
     /**
@@ -76,7 +76,7 @@ class Notice_to_item extends Managed_DataObject
     {
         return array(
             new ColumnDef('notice_id', 'integer', null, false, 'PRI'),
-            new ColumnDef('item_id', 'varchar', 255, false, 'UNI'),
+            new ColumnDef('item_id', 'varchar', 191, false, 'UNI'),
             new ColumnDef('created', 'datetime',  null, false)
         );
     }
index 68c36dfaef5b6710ccbf2771f3aa612a498aba5c..094b65feaa94fd19b38f6b5dd12e6af5b48ebd10 100644 (file)
@@ -8,7 +8,7 @@ class Fave extends Managed_DataObject
     public $__table = 'fave';                            // table name
     public $notice_id;                       // int(4)  primary_key not_null
     public $user_id;                         // int(4)  primary_key not_null
-    public $uri;                             // varchar(255)
+    public $uri;                             // varchar(191)   not 255 because utf8mb4 takes more space   not 255 because utf8mb4 takes more space
     public $created;                         // datetime  multiple_key not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -18,7 +18,7 @@ class Fave extends Managed_DataObject
             'fields' => array(
                 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the favorite'),
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who likes this notice'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index a6e01a8c1b385f1fffdc55b4da3647b8f627efd3..4e4ee69c9739c303a9fc946448304cfbe6fdf077 100644 (file)
@@ -39,10 +39,10 @@ class Photo extends Managed_DataObject
 
     public $__table = 'photo'; // table name
     public $id;                // char (36) // UUID
-    public $uri;               // varchar (255)  // This is the corresponding notice's uri.
-    public $photo_uri;         // varchar (255)
-    public $thumb_uri;         // varchar (255)
-    public $title;             // varchar (255)
+    public $uri;               // varchar (191)  // This is the corresponding notice's uri.   not 255 because utf8mb4 takes more space
+    public $photo_uri;         // varchar (191)   not 255 because utf8mb4 takes more space
+    public $thumb_uri;         // varchar (191)   not 255 because utf8mb4 takes more space
+    public $title;             // varchar (191)   not 255 because utf8mb4 takes more space
     public $description;       // text
     public $profile_id;        // int
 
@@ -66,13 +66,13 @@ class Photo extends Managed_DataObject
                               'not null' => true,
                               'description' => 'UUID'),
                 'uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'photo_uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'photo_uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'profile_id' => array('type' => 'int', 'not null' => true),
             ),
index 4f4e5fbfe44cc415ae66c8410c4686bb93567b2d..5b14e006da40197f69a68f6a08c29b8da12c8af3 100644 (file)
@@ -38,9 +38,9 @@ class GNUsocialPhoto extends Managed_DataObject
     public $id;         // int(11)
     public $notice_id;  // int(11)
     public $album_id;   // int(11)
-    public $uri;        // varchar(255)
-    public $thumb_uri;  // varchar(255)
-       public $title;      // varchar(255)
+    public $uri;        // varchar(191)   not 255 because utf8mb4 takes more space
+    public $thumb_uri;  // varchar(191)   not 255 because utf8mb4 takes more space
+       public $title;      // varchar(191)   not 255 because utf8mb4 takes more space
        public $photo_description; // text
     public $created;           // datetime()   not_null
     public $modified;          // timestamp()   not_null default_CURRENT_TIMESTAMP
@@ -63,9 +63,9 @@ class GNUsocialPhoto extends Managed_DataObject
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for Photo'),
                 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'Notice ID for the related notice'),
                 'album_id' => array('type' => 'int', 'not null' => true, 'description' => 'The parent album ID'),
-                'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'unique address for this photo'),
-                'thumb_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'unique address for this photo thumbnail'),
-                'title' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'The Photo title'),
+                'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'unique address for this photo'),
+                'thumb_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'unique address for this photo thumbnail'),
+                'title' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'The Photo title'),
                 'photo_description' => array('type' => 'text', 'not null' => true, 'description' => 'A description for this photo'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index 8b8c1dbf5a03c7b98e813deb0c1fe924b1edbaf2..acf509a22ac0c84dc73e9534e506dac81cd61711 100644 (file)
@@ -38,7 +38,7 @@ class GNUsocialPhotoAlbum extends Managed_DataObject
     public $__table = 'GNUsocialPhotoAlbum';
     public $album_id;          // int(11) -- Unique identifier for the album
     public $profile_id;        // int(11) -- Profile ID for the owner of the album
-    public $album_name;        // varchar(255) -- Title for this album
+    public $album_name;        // varchar(191) -- Title for this album   not 255 because utf8mb4 takes more space
     public $album_description; // text -- A description of the album
     public $created;           // datetime()   not_null
     public $modified;          // timestamp()   not_null default_CURRENT_TIMESTAMP
@@ -50,7 +50,7 @@ class GNUsocialPhotoAlbum extends Managed_DataObject
             'fields' => array(
                 'album_id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique identifier for the album'),
                 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'Profile ID for the owner of the album'),
-                'album_name' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'Title for this album'),
+                'album_name' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'Title for this album'),
                 'album_description' => array('type' => 'text', 'not null' => true, 'description' => 'A description for this album'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index 564ddce875e40294de0fad6411fb5f2310c616e0..5a9b8de0cb357cc74fc167e92143d43938c06b3d 100644 (file)
@@ -37,9 +37,9 @@ class GNUsocialProfileExtensionField extends Managed_DataObject
     public $__table = 'gnusocialprofileextensionfield';
     public $id;          // int(11)
     public $systemname;  // varchar(64)
-    public $title;       // varchar(255)
+    public $title;       // varchar(191)   not 255 because utf8mb4 takes more space
     public $description; // text
-    public $type;        // varchar(255)
+    public $type;        // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;     // datetime()   not_null
     public $modified;    // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -49,9 +49,9 @@ class GNUsocialProfileExtensionField extends Managed_DataObject
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for extension field'),
                 'systemname' => array('type' => 'varchar', 'not null' => true, 'length' => 64, 'description' => 'field systemname'),
-                'title' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'field title'),
+                'title' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'field title'),
                 'description' => array('type' => 'text', 'not null' => true, 'description' => 'field description'),
-                'type' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'field type'),
+                'type' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'field type'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
index d2dd0469a1f6b4d94b0fe64909ccbe20ca1bec46..09c1f6b8443a0ee17ef11d8d8489228aebfc4156 100644 (file)
@@ -39,8 +39,8 @@ class Video extends Managed_DataObject
 
     public $__table = 'video'; // table name
     public $id;                // char (36) // UUID
-    public $uri;               // varchar (255)  // This is the corresponding notice's uri.
-    public $url;               // varchar (255)
+    public $uri;               // varchar (191)   This is the corresponding notice's uri.   not 255 because utf8mb4 takes more space
+    public $url;               // varchar (191)   not 255 because utf8mb4 takes more space
     public $profile_id;        // int
 
     public static function getByNotice($notice)
@@ -63,10 +63,10 @@ class Video extends Managed_DataObject
                               'not null' => true,
                               'description' => 'UUID'),
                 'uri' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'url' => array('type' => 'varchar',
-                               'length' => 255,
+                               'length' => 191,
                                'not null' => true),
                 'profile_id' => array('type' => 'int', 'not null' => true),
             ),
index 7e825d416deb1fb2c8a628317d63b09c8cdfe465..e4e9f5f6248b848152a7f90f3ea90e785f805a11 100644 (file)
@@ -48,12 +48,12 @@ class Group_message extends Managed_DataObject
 {
     public $__table = 'group_message'; // table name
     public $id;                        // char(36)  primary_key not_null
-    public $uri;                       // varchar(255)
+    public $uri;                       // varchar(191)   not 255 because utf8mb4 takes more space
     public $from_profile;              // int
     public $to_group;                  // int
     public $content;
     public $rendered;
-    public $url;
+    public $url;                       // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                   // datetime()   not_null
     public $modified;                  // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -62,8 +62,8 @@ class Group_message extends Managed_DataObject
         return array(
             'fields' => array(
                 'id' => array('type' => 'char', 'not null' => true, 'length' => 36, 'description' => 'message uuid'),
-                'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'message uri'),
-                'url' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'representation url'),
+                'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'message uri'),
+                'url' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'representation url'),
                 'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'sending profile ID'),
                 'to_group' => array('type' => 'int', 'not null' => true, 'description' => 'receiving group ID'),
                 'content' => array('type' => 'text', 'not null' => true, 'description' => 'message content'),
index 610e32fca757bcff1ff39f16f3652c4ad66a578d..f88ab700874adfee8bbd847f8eee3aee92242151 100644 (file)
@@ -46,11 +46,11 @@ require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
  */
 class Notice_title extends Managed_DataObject
 {
-    const MAXCHARS = 255;
+    const MAXCHARS = 191;   // not 255 because utf8mb4 takes more space
 
     public $__table = 'notice_title'; // table name
     public $notice_id;                         // int(11)  primary_key not_null
-    public $title;                             // varchar(255)
+    public $title;                             // varchar(191)   not 255 because utf8mb4 takes more space
     public $created;                           // datetime()   not_null
     public $modified;                          // timestamp()   not_null default_CURRENT_TIMESTAMP
 
index adc1aa11be6506eb9041a85db5b1924c53180131..d0ac83b56d754d96946c3c6bdd18c86e553c76ed 100644 (file)
@@ -62,7 +62,7 @@ class FeedSub extends Managed_DataObject
     public $__table = 'feedsub';
 
     public $id;
-    public $uri;
+    public $uri;    // varchar(191)   not 255 because utf8mb4 takes more space
 
     // PuSH subscription data
     public $huburi;
@@ -80,7 +80,7 @@ class FeedSub extends Managed_DataObject
         return array(
             'fields' => array(
                 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'FeedSub local unique id'),
-                'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'FeedSub uri'),
+                'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'FeedSub uri'),
                 'huburi' => array('type' => 'text', 'description' => 'FeedSub hub-uri'),
                 'secret' => array('type' => 'text', 'description' => 'FeedSub stored secret'),
                 'sub_state' => array('type' => 'enum("subscribe","active","unsubscribe","inactive","nohub")', 'not null' => true, 'description' => 'subscription state'),
index 96c6986cdf7923b7446e25b43f98179baeec2831..c9d65c56a7a45b09a6beff359f1d2753207eeb23 100644 (file)
@@ -31,8 +31,8 @@ class HubSub extends Managed_DataObject
     public $__table = 'hubsub';
 
     public $hashkey; // sha1(topic . '|' . $callback); (topic, callback) key is too long for myisam in utf8
-    public $topic;
-    public $callback;
+    public $topic;      // varchar(191)   not 255 because utf8mb4 takes more space
+    public $callback;   // varchar(191)   not 255 because utf8mb4 takes more space
     public $secret;
     public $lease;
     public $sub_start;
@@ -55,8 +55,8 @@ class HubSub extends Managed_DataObject
         return array(
             'fields' => array(
                 'hashkey' => array('type' => 'char', 'not null' => true, 'length' => 40, 'description' => 'HubSub hashkey'),
-                'topic' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'HubSub topic'),
-                'callback' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'HubSub callback'),
+                'topic' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'HubSub topic'),
+                'callback' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'HubSub callback'),
                 'secret' => array('type' => 'text', 'description' => 'HubSub stored secret'),
                 'lease' => array('type' => 'int', 'description' => 'HubSub leasetime'),
                 'sub_start' => array('type' => 'datetime', 'description' => 'subscription start'),
index 79098c64048ed31705b54ecfb94259619dad826d..77b1e9bef5ae179a67d8ef24bdf132c11b2de088 100644 (file)
@@ -51,12 +51,12 @@ class Ostatus_profile extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
                 'profile_id' => array('type' => 'integer'),
                 'group_id' => array('type' => 'integer'),
                 'peopletag_id' => array('type' => 'integer'),
-                'feeduri' => array('type' => 'varchar', 'length' => 255),
-                'salmonuri' => array('type' => 'varchar', 'length' => 255),
+                'feeduri' => array('type' => 'varchar', 'length' => 191),
+                'salmonuri' => array('type' => 'varchar', 'length' => 191),
                 'avatar' => array('type' => 'text'),
                 'created' => array('type' => 'datetime', 'not null' => true),
                 'modified' => array('type' => 'datetime', 'not null' => true),
@@ -621,7 +621,7 @@ class Ostatus_profile extends Managed_DataObject
 
         // Get (safe!) HTML and text versions of the content
 
-        $rendered = $this->purify($sourceContent);
+        $rendered = common_purify($sourceContent);
         $content = common_strip_html($rendered);
 
         $shortened = common_shorten_links($content);
@@ -788,7 +788,7 @@ class Ostatus_profile extends Managed_DataObject
 
         // Get (safe!) HTML and text versions of the content
 
-        $rendered = $this->purify($sourceContent);
+        $rendered = common_purify($sourceContent);
         $content = common_strip_html($rendered);
 
         $shortened = common_shorten_links($content);
@@ -914,17 +914,6 @@ class Ostatus_profile extends Managed_DataObject
         return $saved;
     }
 
-    /**
-     * Clean up HTML
-     */
-    protected function purify($html)
-    {
-        require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-        $config = array('safe' => 1,
-                        'deny_attribute' => 'id,style,on*');
-        return htmLawed($html, $config);
-    }
-
     /**
      * Filters a list of recipient ID URIs to just those for local delivery.
      * @param Profile local profile of sender
@@ -1131,6 +1120,11 @@ class Ostatus_profile extends Managed_DataObject
      */
     public static function ensureFeedURL($feed_url, array $hints=array())
     {
+        $oprofile = Ostatus_profile::getKV('feeduri', $feed_url);
+        if ($oprofile instanceof Ostatus_profile) {
+            return $oprofile;
+        }
+
         $discover = new FeedDiscovery();
 
         $feeduri = $discover->discoverFromFeedURL($feed_url);
@@ -1806,8 +1800,8 @@ class Ostatus_profile extends Managed_DataObject
         }
 
         if (!empty($location)) {
-            if (mb_strlen($location) > 255) {
-                $location = mb_substr($note, 0, 255 - 3) . ' … ';
+            if (mb_strlen($location) > 191) {   // not 255 because utf8mb4 takes more space
+                $location = mb_substr($note, 0, 191 - 3) . ' … ';
             }
         }
 
@@ -2098,13 +2092,15 @@ class Ostatus_profile extends Managed_DataObject
                                    'text/html');
 
         $filepath = File::path($filename);
+        $fileurl = File::url($filename);
 
         file_put_contents($filepath, $final);
 
         $file = new File;
 
         $file->filename = $filename;
-        $file->url      = File::url($filename);
+        $file->urlhash  = File::hashurl($fileurl);
+        $file->url      = $fileurl;
         $file->size     = filesize($filepath);
         $file->date     = time();
         $file->mimetype = 'text/html';
index 6cecc323e0986e8247a9b218598b8c857f443ba8..88a6a58383577c8bc11af34801bca4c82aee5f4d 100644 (file)
@@ -40,7 +40,7 @@ class Ostatus_source extends Managed_DataObject
         return array(
             'fields' => array(
                 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'Notice ID relation'),
-                'profile_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'Profile URI'),
+                'profile_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'Profile URI'),
                 'method' => array('type' => 'enum("push","salmon")', 'not null' => true, 'description' => 'source method'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index 5e7d8f35a34517a6ef1937094d373a3c0d497563..2954d8038c9492b00a5db95bdc2abebf92fd08c9 100644 (file)
@@ -245,7 +245,12 @@ class SalmonAction extends Action
                 // Step 4: Is the newly introduced https://example.com/user/1 URI in the list of aliases
                 //         presented by http://example.com/user/1 (i.e. do they both say they are the same identity?)
                 if (in_array($e->object_uri, $doublecheck_aliases)) {
-                    common_debug('These identities both say they are each other: "'.$aliased_uri.'" and "'.$e->object_uri);
+                    common_debug('URIFIX These identities both say they are each other: "'.$aliased_uri.'" and "'.$e->object_uri.'"');
+                    $orig = clone($oprofile);
+                    $oprofile->uri = $e->object_uri;
+                    common_debug('URIFIX Updating Ostatus_profile URI for '.$aliased_uri.' to '.$oprofile->uri);
+                    $oprofile->updateWithKeys($orig, 'uri');    // 'uri' is the primary key column
+                    unset($orig);
                     $this->oprofile = $oprofile;
                     break;  // don't iterate through aliases anymore
                 }
index fda16368376257e57d0ad75b20ea51e4b48c3cdf..3fc655e1705dbd0dca2c9cf4d2a6851e257a18ff 100644 (file)
@@ -31,14 +31,14 @@ class File_oembed extends Managed_DataObject
     public $type;                            // varchar(20)
     public $mimetype;                        // varchar(50)
     public $provider;                        // varchar(50)
-    public $provider_url;                    // varchar(255)
+    public $provider_url;                    // varchar(191)   not 255 because utf8mb4 takes more space
     public $width;                           // int(4)
     public $height;                          // int(4)
     public $html;                            // text()
-    public $title;                           // varchar(255)
+    public $title;                           // varchar(191)   not 255 because utf8mb4 takes more space
     public $author_name;                     // varchar(50)
-    public $author_url;                      // varchar(255)
-    public $url;                             // varchar(255)
+    public $author_url;                      // varchar(191)   not 255 because utf8mb4 takes more space
+    public $url;                             // varchar(191)   not 255 because utf8mb4 takes more space
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
     public static function schemaDef()
@@ -50,14 +50,14 @@ class File_oembed extends Managed_DataObject
                 'type' => array('type' => 'varchar', 'length' => 20, 'description' => 'oEmbed type: photo, video, link, rich'),
                 'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
                 'provider' => array('type' => 'varchar', 'length' => 50, 'description' => 'name of this oEmbed provider'),
-                'provider_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of this oEmbed provider'),
+                'provider_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of this oEmbed provider'),
                 'width' => array('type' => 'int', 'description' => 'width of oEmbed resource when available'),
                 'height' => array('type' => 'int', 'description' => 'height of oEmbed resource when available'),
                 'html' => array('type' => 'text', 'description' => 'html representation of this oEmbed resource when applicable'),
-                'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of oEmbed resource when available'),
+                'title' => array('type' => 'varchar', 'length' => 191, 'description' => 'title of oEmbed resource when available'),
                 'author_name' => array('type' => 'varchar', 'length' => 50, 'description' => 'author name for this oEmbed resource'),
-                'author_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'author URL for this oEmbed resource'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL for this oEmbed resource when applicable (photo, link)'),
+                'author_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'author URL for this oEmbed resource'),
+                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL for this oEmbed resource when applicable (photo, link)'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
             'primary key' => array('file_id'),
index fab35fe2f4eafb09faa95ffc54d374330b45a7d7..0d093f2868fbdb588cf9d27ee9ee065a77b20c62 100644 (file)
@@ -547,13 +547,13 @@ class OpenIDPlugin extends Plugin
                              array(
                                  'fields' => array(
                                      'server_url' => array('type' => 'blob', 'not null' => true),
-                                     'handle' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'default' => ''), // character set latin1,
+                                     'handle' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'default' => ''), // character set latin1,
                                      'secret' => array('type' => 'blob'),
                                      'issued' => array('type' => 'int'),
                                      'lifetime' => array('type' => 'int'),
                                      'assoc_type' => array('type' => 'varchar', 'length' => 64),
                                  ),
-                                 'primary key' => array(array('server_url', 255), 'handle'),
+                                 'primary key' => array(array('server_url', 191), 'handle'),
                              ));
         $schema->ensureTable('oid_nonces',
                              array(
@@ -563,7 +563,7 @@ class OpenIDPlugin extends Plugin
                                      'salt' => array('type' => 'char', 'length' => 40),
                                  ),
                                  'unique keys' => array(
-                                     'oid_nonces_server_url_timestamp_salt_key' => array(array('server_url', 255), 'timestamp', 'salt'),
+                                     'oid_nonces_server_url_timestamp_salt_key' => array(array('server_url', 191), 'timestamp', 'salt'),
                                  ),
                              ));
 
index baff5cd7f96ce8ee24a30c12d2d1cb8f33964d8f..7e53d8ec959893f1dd80ac5724f91175d0765e29 100644 (file)
@@ -13,8 +13,8 @@ class User_openid extends Managed_DataObject
     /* the code below is auto generated do not remove the above tag */
 
     public $__table = 'user_openid';                     // table name
-    public $canonical;                       // varchar(255)  primary_key not_null
-    public $display;                         // varchar(255)  unique_key not_null
+    public $canonical;                       // varchar(191)  primary_key not_null
+    public $display;                         // varchar(191)  unique_key not_null
     public $user_id;                         // int(4)   not_null
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
@@ -26,8 +26,8 @@ class User_openid extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'canonical' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID canonical string'),
-                'display' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID display string'),
+                'canonical' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'OpenID canonical string'),
+                'display' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'OpenID display string'),
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID owner'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index ec09e179e439d3a2704bf70fc82e73ceb7b6933c..575854c332f8eb185ebc02eec77925657e6d3ac3 100644 (file)
@@ -13,7 +13,7 @@ class User_openid_trustroot extends Managed_DataObject
     /* the code below is auto generated do not remove the above tag */
 
     public $__table = 'user_openid_trustroot';                     // table name
-    public $trustroot;                         // varchar(255) primary_key not_null
+    public $trustroot;                         // varchar(191) primary_key not_null   not 255 because utf8mb4 takes more space
     public $user_id;                         // int(4)  primary_key not_null
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
@@ -25,7 +25,7 @@ class User_openid_trustroot extends Managed_DataObject
     {
         return array(
             'fields' => array(
-                'trustroot' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID trustroot string'),
+                'trustroot' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'OpenID trustroot string'),
                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID trustroot owner'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index fe51c667d510f8415af47b0f31cd7877a96b2125..59161704a9dd1def3e7c8d88323bd98fbce636ed 100644 (file)
@@ -47,7 +47,7 @@ class Poll extends Managed_DataObject
 {
     public $__table = 'poll'; // table name
     public $id;          // char(36) primary key not null -> UUID
-    public $uri;
+    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
     public $profile_id;  // int -> profile.id
     public $question;    // text
     public $options;     // text; newline(?)-delimited
@@ -62,7 +62,7 @@ class Poll extends Managed_DataObject
             'description' => 'Per-notice poll data for Poll plugin',
             'fields' => array(
                 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
                 'profile_id' => array('type' => 'int'),
                 'question' => array('type' => 'text'),
                 'options' => array('type' => 'text'),
index 20b7700147bc1006c2a89200b0c2488ed71f5e40..78aec7ea0513c5818c6c0b570522edd1464a7805 100644 (file)
@@ -46,7 +46,7 @@ class Poll_response extends Managed_DataObject
 {
     public $__table = 'poll_response'; // table name
     public $id;          // char(36) primary key not null -> UUID
-    public $uri;          // varchar(255)
+    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
     public $poll_id;     // char(36) -> poll.id UUID
     public $profile_id;  // int -> profile.id
     public $selection;   // int -> choice #
@@ -61,7 +61,7 @@ class Poll_response extends Managed_DataObject
             'description' => 'Record of responses to polls',
             'fields' => array(
                 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of the response'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'UUID to the response notice'),
+                'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'UUID to the response notice'),
                 'poll_id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of poll being responded to'),
                 'profile_id' => array('type' => 'int'),
                 'selection' => array('type' => 'int'),
index f4bf7a9d412ee7c21e072d69b71a00cb4fc372fe..2aa69cf5a301aab87e845402d7647cf8e040e804 100644 (file)
@@ -48,7 +48,7 @@ class QnA_Answer extends Managed_DataObject
 
     public $__table = 'qna_answer'; // table name
     public $id;          // char(36) primary key not null -> UUID
-    public $uri;         // varchar(255)
+    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
     public $question_id; // char(36) -> question.id UUID
     public $profile_id;  // int -> question.id
     public $best;        // (boolean) int -> whether the question asker has marked this as the best answer
@@ -71,7 +71,7 @@ class QnA_Answer extends Managed_DataObject
                 ),
                 'uri'      => array(
                     'type'        => 'varchar',
-                    'length'      => 255,
+                    'length'      => 191,
                     'not null'    => true,
                     'description' => 'UUID to the answer notice',
                 ),
index b421b0aed19a952c98ea5a69ff2762e84afe944d..b5318386777b50dcd2569007bde40303565fa7ad 100644 (file)
@@ -48,7 +48,7 @@ class QnA_Question extends Managed_DataObject
 
     public $__table = 'qna_question'; // table name
     public $id;          // char(36) primary key not null -> UUID
-    public $uri;
+    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
     public $profile_id;  // int -> profile.id
     public $title;       // text
     public $description; // text
@@ -71,7 +71,7 @@ class QnA_Question extends Managed_DataObject
                 ),
                 'uri' => array(
                     'type'     => 'varchar',
-                    'length'   => 255,
+                    'length'   => 191,
                     'not null' => true
                 ),
                 'profile_id'  => array('type' => 'int'),
index 823094f269eace621d530cf66a4ca0e80f4ff46f..55f73783fa4785bf4d2ee8ce8201712000bca83f 100644 (file)
@@ -175,7 +175,7 @@ class RSSCloudPlugin extends Plugin
             array(
                 'fields' => array(
                     'subscribed' => array('type' => 'int', 'not null' => true),
-                    'url' => array('type' => 'varchar', 'length' => '255', 'not null' => true),
+                    'url' => array('type' => 'varchar', 'length' => '191', 'not null' => true),
                     'failures' => array('type' => 'int', 'not null' => true, 'default' => 0),
                     'created' => array('type' => 'datetime', 'not null' => true),
                     'modified' => array('type' => 'timestamp', 'not null' => true),
index 5d6f0ff99afc75272168bfcd536a05852a1417a4..7541593433f905c9209bf9aaf2f2eb203585c8c2 100644 (file)
@@ -53,9 +53,9 @@ class Realtime_channel extends Managed_DataObject
     public $__table = 'realtime_channel'; // table name
 
     public $user_id;       // int -> user.id, can be null
-    public $action;        // string
-    public $arg1;          // argument
-    public $arg2;          // argument, usually null
+    public $action;        // varchar(191)                  not 255 because utf8mb4 takes more space
+    public $arg1;          // varchar(191)   argument       not 255 because utf8mb4 takes more space
+    public $arg2;          // varchar(191)   usually null   not 255 because utf8mb4 takes more space
     public $channel_key;   // 128-bit shared secret key
     public $audience;      // listener count
     public $created;       // created date
@@ -73,15 +73,15 @@ class Realtime_channel extends Managed_DataObject
                                    'not null' => false,
                                    'description' => 'user viewing page; can be null'),
                 'action' => array('type' => 'varchar',
-                                  'length' => 255,
+                                  'length' => 191,
                                   'not null' => true,
                                   'description' => 'page being viewed'),
                 'arg1' => array('type' => 'varchar',
-                                'length' => 255,
+                                'length' => 191,
                                 'not null' => false,
                                 'description' => 'page argument, like username or tag'),
                 'arg2' => array('type' => 'varchar',
-                                'length' => 255,
+                                'length' => 191,
                                 'not null' => false,
                                 'description' => 'second page argument, like tag for showstream'),
                 'channel_key' => array('type' => 'varchar',
index 9a20536147e3da8be62e0164e6f59808f5c2de8b..28f60b9b3e8db8b11fe447c15c5ef2288c8ed1ed 100644 (file)
@@ -52,7 +52,7 @@ class Twitter_synch_status extends Managed_DataObject
 {
     public $__table = 'twitter_synch_status'; // table name
     public $foreign_id;                      // bigint primary_key not_null
-    public $timeline;                        // varchar(255)  primary_key not_null
+    public $timeline;                        // varchar(191)  primary_key not_null   not 255 because utf8mb4 takes more space
     public $last_id;                         // bigint not_null
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
@@ -62,7 +62,7 @@ class Twitter_synch_status extends Managed_DataObject
         return array(
             'fields' => array(
                 'foreign_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'Foreign message ID'),
-                'timeline' => array('type' => 'varchar', 'length' => 255, 'description' => 'timeline name'),
+                'timeline' => array('type' => 'varchar', 'length' => 191, 'description' => 'timeline name'),
                 'last_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'last id fetched'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
index 254931e5fbc0c9d0286f1f2eb18ca7474171347f..2bbc06d7384b07529701f43a04de09a55647d164 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * GNU social - a federating social network
  *
- * Plugin to make thumbnails of video files with ffmpeg
+ * Plugin to make thumbnails of video files with avconv
  *
  * PHP version 5
  *
@@ -31,10 +31,13 @@ if (!defined('GNUSOCIAL')) { exit(1); }
 
 /*
  * Dependencies:
- *  php5-ffmpeg
+ *  avconv (external program call)
  *  php5-gd
  *
- * Video support will depend on your ffmpeg.
+ * Todo:
+ *  Make sure we support ffmpeg too, so we're not super Debian oriented.
+ *
+ * Video support will depend on your avconv.
  */
 
 class VideoThumbnailsPlugin extends Plugin
@@ -48,27 +51,17 @@ class VideoThumbnailsPlugin extends Plugin
     {
         // The calling function might accidentally pass application/ogg videos.
         // If that's a problem, let's fix it in the calling function.
-        if ($media !== 'video') {
+        if ($media !== 'video' || empty($file->filename)) {
             return true;
         }
 
-        $movie = new ffmpeg_movie($file->getPath(), false);
+        // Let's save our frame to a temporary file. If we fail, remove it.
+        $imgPath = tempnam(sys_get_temp_dir(), 'socialthumb-');
 
-        $frames = $movie->getFrameCount();
-        if ($frames > 0) {
-            $frame = $movie->getFrame(floor($frames/2));
-        } else {
-            $frame = $movie->getNextKeyFrame();
-        }
+        $result = exec('avconv -i '.escapeshellarg($file->getPath()).' -vcodec mjpeg -vframes 1 -f image2 -an '.escapeshellarg($imgPath));
 
-        // We failed to get a frame.
-        if (!$frame instanceof ffmpeg_frame) {
-            return true;
-        }
-
-        // Let's save our frame to a temporary file. If we fail, remove it.
-        $imgPath = tempnam(sys_get_temp_dir(), 'socialthumb');
-        if (!imagejpeg($frame->toGDImage(), $imgPath)) {
+        if (!getimagesize($imgPath)) {
+            common_debug('exec of "avconv" produced a bad/nonexisting image it seems');
             @unlink($imgPath);
             return true;
         }
diff --git a/scripts/clean_file_table.php b/scripts/clean_file_table.php
new file mode 100755 (executable)
index 0000000..573abf1
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$shortoptions = 'y';
+$longoptions = array('yes');
+
+$helptext = <<<END_OF_HELP
+clean_file_table.php [options]
+Deletes all local files where the filename cannot be found in the filesystem.
+
+  -y --yes      do not wait for confirmation
+
+Will print '.' for each file, except for deleted ones which are marked as 'x'.
+
+END_OF_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+if (!have_option('y', 'yes')) {
+    print "About to delete local file entries where the file cannot be found. Are you sure? [y/N] ";
+    $response = fgets(STDIN);
+    if (strtolower(trim($response)) != 'y') {
+        print "Aborting.\n";
+        exit(0);
+    }
+}
+
+print "Deleting";
+$file = new File();
+$file->whereAdd('filename IS NOT NULL');        // local files
+$file->whereAdd('filehash IS NULL', 'AND');     // without filehash value
+if ($file->find()) {
+    while ($file->fetch()) {
+        try {
+            $file->getPath();
+            print '.';
+        } catch (FileNotFoundException $e) {
+            $file->delete();
+            print 'x';
+        }
+    }
+}
+print "\nDONE.\n";
diff --git a/scripts/clean_profiles.php b/scripts/clean_profiles.php
new file mode 100755 (executable)
index 0000000..470d6c1
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$shortoptions = 'y';
+$longoptions = array('yes');
+
+$helptext = <<<END_OF_HELP
+clean_profiles.php [options]
+Deletes all profile table entries where the profile does not occur in the
+notice table, is not a group and is not a local user. Very MySQL specific I think.
+
+WARNING: This has not been tested thoroughly. Maybe we've missed a table to compare somewhere.
+
+  -y --yes      do not wait for confirmation
+
+END_OF_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+if (!have_option('y', 'yes')) {
+    print "About to delete profiles that we think are useless to save. Are you sure? [y/N] ";
+    $response = fgets(STDIN);
+    if (strtolower(trim($response)) != 'y') {
+        print "Aborting.\n";
+        exit(0);
+    }
+}
+
+print "Deleting";
+$profile = new Profile();
+$profile->query('SELECT * FROM profile WHERE ' .
+                'NOT (SELECT COUNT(*) FROM notice WHERE profile_id=profile.id) ' .
+                'AND NOT (SELECT COUNT(*) FROM user WHERE user.id=profile.id) ' .
+                'AND NOT (SELECT COUNT(*) FROM user_group WHERE user_group.profile_id=profile.id) ' .
+                'AND NOT (SELECT COUNT(*) FROM subscription WHERE subscriber=profile.id OR subscribed=profile.id) ');
+while ($profile->fetch()) {
+    echo ' '.$profile->getID().':'.$profile->getNickname();
+    $profile->delete();
+}
+print "\nDONE.\n";
index c221a495af1cc04489643ce24bb3ce8a10bc1cd8..692eaac17a40b8d083b4b1ff8e4be6ecd6932780 100644 (file)
@@ -48,6 +48,7 @@ function main()
         fixupFileGeometry();
         deleteLocalFileThumbnailsWithoutFilename();
         deleteMissingLocalFileThumbnails();
+        setFilehashOnLocalFiles();
 
         initGroupProfileId();
         initLocalGroup();
@@ -490,7 +491,9 @@ function deleteMissingLocalFileThumbnails()
     // Checking if there were any File_thumbnail entries without filename
     if ($thumbs->find()) {
         while ($thumbs->fetch()) {
-            if (!file_exists(File_thumbnail::path($thumbs->filename))) {
+            try {
+                $thumbs->getPath();
+            } catch (FileNotFoundException $e) {
                 $thumbs->delete();
             }
         }
@@ -499,4 +502,30 @@ function deleteMissingLocalFileThumbnails()
     printfnq("DONE.\n");
 }
 
+/*
+ * Files are now stored with their hash, so let's generate for previously uploaded files.
+ */
+function setFilehashOnLocalFiles()
+{
+    printfnq('Ensuring all local files have the filehash field set...');
+
+    $file = new File();
+    $file->whereAdd('filename IS NOT NULL');        // local files
+    $file->whereAdd('filehash IS NULL', 'AND');     // without filehash value
+
+    if ($file->find()) {
+        while ($file->fetch()) {
+            try {
+                $orig = clone($file);
+                $file->filehash = hash_file(File::FILEHASH_ALG, $file->getPath());
+                $file->update($orig);
+            } catch (FileNotFoundException $e) {
+                echo "\n    WARNING: file ID {$file->id} does not exist on path '{$e->path}'. Clean up the file table?";
+            }
+        }
+    }
+
+    printfnq("DONE.\n");
+}
+
 main();
index cfc644d96be160774339f4bf2b900338776b4bfa..7d28cee8df4d387a70a48d262692e0d81e990389 100644 (file)
@@ -713,6 +713,10 @@ font-style:italic;
     overflow-y: auto;
 }
 
+.notice .e-content img {
+    max-width: 100%;
+}
+
 .notice-options {
     margin-bottom: 7px;
     margin-top: 12px;