From c07f22104094d26f7f6266c2b59f7999030fda1a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 10:42:31 -0800 Subject: check if other user exists before unsub --- classes/User.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/User.php b/classes/User.php index 484dc8c82..6708d95b6 100644 --- a/classes/User.php +++ b/classes/User.php @@ -625,7 +625,11 @@ class User extends Memcached_DataObject // Cancel their subscription, if it exists - subs_unsubscribe_to($other->getUser(),$this->getProfile()); + $otherUser = User::staticGet('id', $other->id); + + if (!empty($otherUser)) { + subs_unsubscribe_to($otherUser, $this->getProfile()); + } $block->query('COMMIT'); -- cgit v1.2.3-54-g00ecf From c32682413530e5f2f4a85bd9397c533ba17f7e86 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 13:59:03 -0800 Subject: add user-location-prefs data objects --- classes/User_location_prefs.php | 48 +++++++++++++++++++++++++++++++++++++++++ classes/statusnet.ini | 12 +++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100755 classes/User_location_prefs.php (limited to 'classes') diff --git a/classes/User_location_prefs.php b/classes/User_location_prefs.php new file mode 100755 index 000000000..52cb254ba --- /dev/null +++ b/classes/User_location_prefs.php @@ -0,0 +1,48 @@ +. + * + * @category Data + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class User_location_prefs extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'user_location_prefs'; // table name + public $user_id; // int(4) primary_key not_null + public $share_location; // tinyint(1) default_1 + public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00 + public $modified; // timestamp not_null default_CURRENT_TIMESTAMP + + /* Static get */ + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User_location_prefs',$k,$v); } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE +} diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 2cc37dbfe..ac69403a4 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -1,4 +1,3 @@ - [avatar] profile_id = 129 original = 17 @@ -564,4 +563,13 @@ modified = 384 [user_openid__keys] trustroot = K -user_id = K \ No newline at end of file +user_id = K + +[user_location_prefs] +user_id = 129 +share_location = 17 +created = 142 +modified = 384 + +[user_location_prefs__keys] +user_id = K -- cgit v1.2.3-54-g00ecf From bbf516b96594770c5dc0dea7f9b15937d7c9a237 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 13:59:31 -0800 Subject: turn off exe bits --- classes/User_location_prefs.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/User_location_prefs.php (limited to 'classes') diff --git a/classes/User_location_prefs.php b/classes/User_location_prefs.php old mode 100755 new mode 100644 -- cgit v1.2.3-54-g00ecf From bb93d6b1c7c697891baca7082261ee694727f161 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 14:21:07 -0800 Subject: remove namespace setting from location; it's unused --- actions/newnotice.php | 43 ++++++++++++++++++++++++------------------- actions/profilesettings.php | 5 +++++ classes/User.php | 16 ++++++++++++++++ lib/default.php | 2 +- 4 files changed, 46 insertions(+), 20 deletions(-) (limited to 'classes') diff --git a/actions/newnotice.php b/actions/newnotice.php index c014f1781..8591522dc 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -164,19 +164,6 @@ class NewnoticeAction extends Action $replyto = 'false'; } - $lat = $this->trimmed('lat'); - $lon = $this->trimmed('lon'); - $location_id = $this->trimmed('location_id'); - $location_ns = $this->trimmed('location_ns'); - - if (!empty($lat) && !empty($lon) && empty($location_id)) { - $location = Location::fromLatLon($lat, $lon); - if (!empty($location)) { - $location_id = $location->location_id; - $location_ns = $location->location_ns; - } - } - $upload = null; $upload = MediaFile::fromUpload('attach'); @@ -195,12 +182,30 @@ class NewnoticeAction extends Action } } - $notice = Notice::saveNew($user->id, $content_shortened, 'web', - array('reply_to' => ($replyto == 'false') ? null : $replyto, - 'lat' => $lat, - 'lon' => $lon, - 'location_id' => $location_id, - 'location_ns' => $location_ns)); + $options = array('reply_to' => ($replyto == 'false') ? null : $replyto); + + if ($user->shareLocation()) { + + $lat = $this->trimmed('lat'); + $lon = $this->trimmed('lon'); + $location_id = $this->trimmed('location_id'); + $location_ns = $this->trimmed('location_ns'); + + if (!empty($lat) && !empty($lon) && empty($location_id)) { + $location = Location::fromLatLon($lat, $lon); + if (!empty($location)) { + $location_id = $location->location_id; + $location_ns = $location->location_ns; + } + } + + $options['lat'] = $lat; + $options['lon'] = $lon; + $options['location_id'] = $location_id; + $options['location_ns'] = $location_ns; + } + + $notice = Notice::saveNew($user->id, $content_shortened, 'web', $options); if (isset($upload)) { $upload->attachToNotice($notice); diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 359664096..58bf838d7 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -133,6 +133,11 @@ class ProfilesettingsAction extends AccountSettingsAction ($this->arg('location')) ? $this->arg('location') : $profile->location, _('Where you are, like "City, State (or Region), Country"')); $this->elementEnd('li'); + $this->elementStart('li'); + $this->checkbox('sharelocation', _('Share my current location when posting notices'), + ($this->arg('sharelocation')) ? + $this->arg('sharelocation') : $user->shareLocation()); + $this->elementEnd('li'); Event::handle('EndProfileFormData', array($this)); $this->elementStart('li'); $this->input('tags', _('Tags'), diff --git a/classes/User.php b/classes/User.php index 6708d95b6..2bcb7c2a0 100644 --- a/classes/User.php +++ b/classes/User.php @@ -996,4 +996,20 @@ class User extends Memcached_DataObject return $ids; } + + function shareLocation() + { + $share = true; + + $prefs = User_location_prefs::staticGet('user_id', $this->id); + + if (empty($prefs)) { + $share = common_config('location', 'share'); + } else { + $share = $prefs->share_location; + $prefs->free(); + } + + return $share; + } } diff --git a/lib/default.php b/lib/default.php index 42d4623b1..b5eda7b2c 100644 --- a/lib/default.php +++ b/lib/default.php @@ -226,7 +226,7 @@ $default = 'message' => array('contentlimit' => null), 'location' => - array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth + array(), 'omb' => array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates 'logincommand' => -- cgit v1.2.3-54-g00ecf From 29a1669c01135faf125b2e53718a4112f14525fd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 14:43:14 -0800 Subject: user_id is primary key for user_location_prefs --- classes/statusnet.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/statusnet.ini b/classes/statusnet.ini index ac69403a4..35a000aac 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -572,4 +572,5 @@ created = 142 modified = 384 [user_location_prefs__keys] -user_id = K +user_id = N + -- cgit v1.2.3-54-g00ecf From 39bdda9c7e7ee7571298c84c406a9dd74805f050 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 14:43:34 -0800 Subject: More configuration options for location sharing --- classes/User.php | 26 +++++++++++++++++--------- lib/default.php | 3 ++- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'classes') diff --git a/classes/User.php b/classes/User.php index 2bcb7c2a0..34151778c 100644 --- a/classes/User.php +++ b/classes/User.php @@ -999,17 +999,25 @@ class User extends Memcached_DataObject function shareLocation() { - $share = true; + $cfg = common_config('location', 'share'); - $prefs = User_location_prefs::staticGet('user_id', $this->id); + if ($cfg == 'always') { + return true; + } else if ($cfg == 'never') { + return false; + } else { // user + $share = true; - if (empty($prefs)) { - $share = common_config('location', 'share'); - } else { - $share = $prefs->share_location; - $prefs->free(); - } + $prefs = User_location_prefs::staticGet('user_id', $this->id); - return $share; + if (empty($prefs)) { + $share = common_config('location', 'sharedefault'); + } else { + $share = $prefs->share_location; + $prefs->free(); + } + + return $share; + } } } diff --git a/lib/default.php b/lib/default.php index b5eda7b2c..8a70ed3fa 100644 --- a/lib/default.php +++ b/lib/default.php @@ -226,7 +226,8 @@ $default = 'message' => array('contentlimit' => null), 'location' => - array(), + array('share' => 'user', // whether to share location; 'always', 'user', 'never' + 'sharedefault' => true), 'omb' => array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates 'logincommand' => -- cgit v1.2.3-54-g00ecf From ca6669538a16f36f92df918d679671b95b1859ac Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 15:13:15 -0800 Subject: Move location-argument-handling code into a single function Moved the important parts of the location-argument-handling stuff to a single function. Handles defaults and overrides correctly, and easy to use. Changed Web and API channels to use it. --- actions/apistatusesupdate.php | 20 +++++++-------- actions/newnotice.php | 22 +++++----------- classes/Notice.php | 59 +++++++++++++++++++++++++++++++++---------- 3 files changed, 61 insertions(+), 40 deletions(-) (limited to 'classes') diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index dabbea92f..f594bbf39 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -203,12 +203,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction } } - $location = null; - - if (!empty($this->lat) && !empty($this->lon)) { - $location = Location::fromLatLon($this->lat, $this->lon); - } - $upload = null; try { @@ -235,11 +229,15 @@ class ApiStatusesUpdateAction extends ApiAuthAction $options = array('reply_to' => $reply_to); - if (!empty($location)) { - $options['lat'] = $location->lat; - $options['lon'] = $location->lon; - $options['location_id'] = $location->location_id; - $options['location_ns'] = $location->location_ns; + if ($this->user->shareLocation()) { + + $locOptions = Notice::locationOptions($this->lat, + $this->lon, + null, + null, + $this->user->getProfile()); + + $options = array_merge($options, $locOptions); } $this->notice = diff --git a/actions/newnotice.php b/actions/newnotice.php index 8591522dc..2d9f0ff79 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -186,23 +186,13 @@ class NewnoticeAction extends Action if ($user->shareLocation()) { - $lat = $this->trimmed('lat'); - $lon = $this->trimmed('lon'); - $location_id = $this->trimmed('location_id'); - $location_ns = $this->trimmed('location_ns'); - - if (!empty($lat) && !empty($lon) && empty($location_id)) { - $location = Location::fromLatLon($lat, $lon); - if (!empty($location)) { - $location_id = $location->location_id; - $location_ns = $location->location_ns; - } - } + $locOptions = Notice::locationOptions($this->trimmed('lat'), + $this->trimmed('lon'), + $this->trimmed('location_id'), + $this->trimmed('location_ns'), + $user->getProfile()); - $options['lat'] = $lat; - $options['lon'] = $lon; - $options['location_id'] = $location_id; - $options['location_ns'] = $location_ns; + $options = array_merge($options, $locOptions); } $notice = Notice::saveNew($user->id, $content_shortened, 'web', $options); diff --git a/classes/Notice.php b/classes/Notice.php index 7651d8bd5..9f68c5255 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -289,21 +289,11 @@ class Notice extends Memcached_DataObject if (!empty($lat) && !empty($lon)) { $notice->lat = $lat; $notice->lon = $lon; + } + + if (!empty($location_ns) && !empty($location_id)) { $notice->location_id = $location_id; $notice->location_ns = $location_ns; - } else if (!empty($location_ns) && !empty($location_id)) { - $location = Location::fromId($location_id, $location_ns); - if (!empty($location)) { - $notice->lat = $location->lat; - $notice->lon = $location->lon; - $notice->location_id = $location_id; - $notice->location_ns = $location_ns; - } - } else { - $notice->lat = $profile->lat; - $notice->lon = $profile->lon; - $notice->location_id = $profile->location_id; - $notice->location_ns = $profile->location_ns; } if (Event::handle('StartNoticeSave', array(&$notice))) { @@ -1429,4 +1419,47 @@ class Notice extends Memcached_DataObject return $ids; } + + function locationOptions($lat, $lon, $location_id, $location_ns, $profile = null) + { + $options = array(); + + if (!empty($location_id) && !empty($location_ns)) { + + $options['location_id'] = $location_id; + $options['location_ns'] = $location_ns; + + $location = Location::fromId($location_id, $location_ns); + + if (!empty($location)) { + $options['lat'] = $location->lat; + $options['lon'] = $location->lon; + } + + } else if (!empty($lat) && !empty($lon)) { + + $options['lat'] = $lat; + $options['lon'] = $lon; + + $location = Location::fromLatLon($lat, $lon); + + if (!empty($location)) { + $options['location_id'] = $location->location_id; + $options['location_ns'] = $location->location_ns; + } + } else if (!empty($profile)) { + + if (isset($profile->lat) && isset($profile->lon)) { + $options['lat'] = $profile->lat; + $options['lon'] = $profile->lon; + } + + if (isset($profile->location_id) && isset($profile->location_ns)) { + $options['location_id'] = $profile->location_id; + $options['location_ns'] = $profile->location_ns; + } + } + + return $options; + } } -- cgit v1.2.3-54-g00ecf From 51a33dc66da9ff3412f767cf8451f6aeaf7696ea Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 13:59:03 -0800 Subject: add user-location-prefs data objects --- classes/User_location_prefs.php | 48 +++++++++++++++++++++++++++++++++++++++++ classes/statusnet.ini | 12 +++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100755 classes/User_location_prefs.php (limited to 'classes') diff --git a/classes/User_location_prefs.php b/classes/User_location_prefs.php new file mode 100755 index 000000000..52cb254ba --- /dev/null +++ b/classes/User_location_prefs.php @@ -0,0 +1,48 @@ +. + * + * @category Data + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class User_location_prefs extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'user_location_prefs'; // table name + public $user_id; // int(4) primary_key not_null + public $share_location; // tinyint(1) default_1 + public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00 + public $modified; // timestamp not_null default_CURRENT_TIMESTAMP + + /* Static get */ + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User_location_prefs',$k,$v); } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE +} diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 2cc37dbfe..ac69403a4 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -1,4 +1,3 @@ - [avatar] profile_id = 129 original = 17 @@ -564,4 +563,13 @@ modified = 384 [user_openid__keys] trustroot = K -user_id = K \ No newline at end of file +user_id = K + +[user_location_prefs] +user_id = 129 +share_location = 17 +created = 142 +modified = 384 + +[user_location_prefs__keys] +user_id = K -- cgit v1.2.3-54-g00ecf From 33786b2c4e172f9aebf03013c88685f417028bc0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 13:59:31 -0800 Subject: turn off exe bits --- classes/User_location_prefs.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/User_location_prefs.php (limited to 'classes') diff --git a/classes/User_location_prefs.php b/classes/User_location_prefs.php old mode 100755 new mode 100644 -- cgit v1.2.3-54-g00ecf From c1e3b2f032d2a63298d4cde46b8dc17637634750 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 14:21:07 -0800 Subject: remove namespace setting from location; it's unused --- actions/newnotice.php | 43 ++++++++++++++++++++++++------------------- actions/profilesettings.php | 5 +++++ classes/User.php | 16 ++++++++++++++++ lib/default.php | 2 +- 4 files changed, 46 insertions(+), 20 deletions(-) (limited to 'classes') diff --git a/actions/newnotice.php b/actions/newnotice.php index c014f1781..8591522dc 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -164,19 +164,6 @@ class NewnoticeAction extends Action $replyto = 'false'; } - $lat = $this->trimmed('lat'); - $lon = $this->trimmed('lon'); - $location_id = $this->trimmed('location_id'); - $location_ns = $this->trimmed('location_ns'); - - if (!empty($lat) && !empty($lon) && empty($location_id)) { - $location = Location::fromLatLon($lat, $lon); - if (!empty($location)) { - $location_id = $location->location_id; - $location_ns = $location->location_ns; - } - } - $upload = null; $upload = MediaFile::fromUpload('attach'); @@ -195,12 +182,30 @@ class NewnoticeAction extends Action } } - $notice = Notice::saveNew($user->id, $content_shortened, 'web', - array('reply_to' => ($replyto == 'false') ? null : $replyto, - 'lat' => $lat, - 'lon' => $lon, - 'location_id' => $location_id, - 'location_ns' => $location_ns)); + $options = array('reply_to' => ($replyto == 'false') ? null : $replyto); + + if ($user->shareLocation()) { + + $lat = $this->trimmed('lat'); + $lon = $this->trimmed('lon'); + $location_id = $this->trimmed('location_id'); + $location_ns = $this->trimmed('location_ns'); + + if (!empty($lat) && !empty($lon) && empty($location_id)) { + $location = Location::fromLatLon($lat, $lon); + if (!empty($location)) { + $location_id = $location->location_id; + $location_ns = $location->location_ns; + } + } + + $options['lat'] = $lat; + $options['lon'] = $lon; + $options['location_id'] = $location_id; + $options['location_ns'] = $location_ns; + } + + $notice = Notice::saveNew($user->id, $content_shortened, 'web', $options); if (isset($upload)) { $upload->attachToNotice($notice); diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 359664096..58bf838d7 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -133,6 +133,11 @@ class ProfilesettingsAction extends AccountSettingsAction ($this->arg('location')) ? $this->arg('location') : $profile->location, _('Where you are, like "City, State (or Region), Country"')); $this->elementEnd('li'); + $this->elementStart('li'); + $this->checkbox('sharelocation', _('Share my current location when posting notices'), + ($this->arg('sharelocation')) ? + $this->arg('sharelocation') : $user->shareLocation()); + $this->elementEnd('li'); Event::handle('EndProfileFormData', array($this)); $this->elementStart('li'); $this->input('tags', _('Tags'), diff --git a/classes/User.php b/classes/User.php index 6708d95b6..2bcb7c2a0 100644 --- a/classes/User.php +++ b/classes/User.php @@ -996,4 +996,20 @@ class User extends Memcached_DataObject return $ids; } + + function shareLocation() + { + $share = true; + + $prefs = User_location_prefs::staticGet('user_id', $this->id); + + if (empty($prefs)) { + $share = common_config('location', 'share'); + } else { + $share = $prefs->share_location; + $prefs->free(); + } + + return $share; + } } diff --git a/lib/default.php b/lib/default.php index 42d4623b1..b5eda7b2c 100644 --- a/lib/default.php +++ b/lib/default.php @@ -226,7 +226,7 @@ $default = 'message' => array('contentlimit' => null), 'location' => - array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth + array(), 'omb' => array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates 'logincommand' => -- cgit v1.2.3-54-g00ecf From 6a6d88f0f4641f294a5c513c6aacba604e37222f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 14:43:14 -0800 Subject: user_id is primary key for user_location_prefs --- classes/statusnet.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/statusnet.ini b/classes/statusnet.ini index ac69403a4..35a000aac 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -572,4 +572,5 @@ created = 142 modified = 384 [user_location_prefs__keys] -user_id = K +user_id = N + -- cgit v1.2.3-54-g00ecf From 97f611107a9620f0e01e6c00c91cd1edea66d981 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 14:43:34 -0800 Subject: More configuration options for location sharing --- classes/User.php | 26 +++++++++++++++++--------- lib/default.php | 3 ++- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'classes') diff --git a/classes/User.php b/classes/User.php index 2bcb7c2a0..34151778c 100644 --- a/classes/User.php +++ b/classes/User.php @@ -999,17 +999,25 @@ class User extends Memcached_DataObject function shareLocation() { - $share = true; + $cfg = common_config('location', 'share'); - $prefs = User_location_prefs::staticGet('user_id', $this->id); + if ($cfg == 'always') { + return true; + } else if ($cfg == 'never') { + return false; + } else { // user + $share = true; - if (empty($prefs)) { - $share = common_config('location', 'share'); - } else { - $share = $prefs->share_location; - $prefs->free(); - } + $prefs = User_location_prefs::staticGet('user_id', $this->id); - return $share; + if (empty($prefs)) { + $share = common_config('location', 'sharedefault'); + } else { + $share = $prefs->share_location; + $prefs->free(); + } + + return $share; + } } } diff --git a/lib/default.php b/lib/default.php index b5eda7b2c..8a70ed3fa 100644 --- a/lib/default.php +++ b/lib/default.php @@ -226,7 +226,8 @@ $default = 'message' => array('contentlimit' => null), 'location' => - array(), + array('share' => 'user', // whether to share location; 'always', 'user', 'never' + 'sharedefault' => true), 'omb' => array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates 'logincommand' => -- cgit v1.2.3-54-g00ecf From e3789be03f9e2d20aa74da1a10c4090b260d3359 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 15:13:15 -0800 Subject: Move location-argument-handling code into a single function Moved the important parts of the location-argument-handling stuff to a single function. Handles defaults and overrides correctly, and easy to use. Changed Web and API channels to use it. --- actions/apistatusesupdate.php | 20 +++++++-------- actions/newnotice.php | 22 +++++----------- classes/Notice.php | 59 +++++++++++++++++++++++++++++++++---------- 3 files changed, 61 insertions(+), 40 deletions(-) (limited to 'classes') diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index dabbea92f..f594bbf39 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -203,12 +203,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction } } - $location = null; - - if (!empty($this->lat) && !empty($this->lon)) { - $location = Location::fromLatLon($this->lat, $this->lon); - } - $upload = null; try { @@ -235,11 +229,15 @@ class ApiStatusesUpdateAction extends ApiAuthAction $options = array('reply_to' => $reply_to); - if (!empty($location)) { - $options['lat'] = $location->lat; - $options['lon'] = $location->lon; - $options['location_id'] = $location->location_id; - $options['location_ns'] = $location->location_ns; + if ($this->user->shareLocation()) { + + $locOptions = Notice::locationOptions($this->lat, + $this->lon, + null, + null, + $this->user->getProfile()); + + $options = array_merge($options, $locOptions); } $this->notice = diff --git a/actions/newnotice.php b/actions/newnotice.php index 8591522dc..2d9f0ff79 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -186,23 +186,13 @@ class NewnoticeAction extends Action if ($user->shareLocation()) { - $lat = $this->trimmed('lat'); - $lon = $this->trimmed('lon'); - $location_id = $this->trimmed('location_id'); - $location_ns = $this->trimmed('location_ns'); - - if (!empty($lat) && !empty($lon) && empty($location_id)) { - $location = Location::fromLatLon($lat, $lon); - if (!empty($location)) { - $location_id = $location->location_id; - $location_ns = $location->location_ns; - } - } + $locOptions = Notice::locationOptions($this->trimmed('lat'), + $this->trimmed('lon'), + $this->trimmed('location_id'), + $this->trimmed('location_ns'), + $user->getProfile()); - $options['lat'] = $lat; - $options['lon'] = $lon; - $options['location_id'] = $location_id; - $options['location_ns'] = $location_ns; + $options = array_merge($options, $locOptions); } $notice = Notice::saveNew($user->id, $content_shortened, 'web', $options); diff --git a/classes/Notice.php b/classes/Notice.php index 7651d8bd5..9f68c5255 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -289,21 +289,11 @@ class Notice extends Memcached_DataObject if (!empty($lat) && !empty($lon)) { $notice->lat = $lat; $notice->lon = $lon; + } + + if (!empty($location_ns) && !empty($location_id)) { $notice->location_id = $location_id; $notice->location_ns = $location_ns; - } else if (!empty($location_ns) && !empty($location_id)) { - $location = Location::fromId($location_id, $location_ns); - if (!empty($location)) { - $notice->lat = $location->lat; - $notice->lon = $location->lon; - $notice->location_id = $location_id; - $notice->location_ns = $location_ns; - } - } else { - $notice->lat = $profile->lat; - $notice->lon = $profile->lon; - $notice->location_id = $profile->location_id; - $notice->location_ns = $profile->location_ns; } if (Event::handle('StartNoticeSave', array(&$notice))) { @@ -1429,4 +1419,47 @@ class Notice extends Memcached_DataObject return $ids; } + + function locationOptions($lat, $lon, $location_id, $location_ns, $profile = null) + { + $options = array(); + + if (!empty($location_id) && !empty($location_ns)) { + + $options['location_id'] = $location_id; + $options['location_ns'] = $location_ns; + + $location = Location::fromId($location_id, $location_ns); + + if (!empty($location)) { + $options['lat'] = $location->lat; + $options['lon'] = $location->lon; + } + + } else if (!empty($lat) && !empty($lon)) { + + $options['lat'] = $lat; + $options['lon'] = $lon; + + $location = Location::fromLatLon($lat, $lon); + + if (!empty($location)) { + $options['location_id'] = $location->location_id; + $options['location_ns'] = $location->location_ns; + } + } else if (!empty($profile)) { + + if (isset($profile->lat) && isset($profile->lon)) { + $options['lat'] = $profile->lat; + $options['lon'] = $profile->lon; + } + + if (isset($profile->location_id) && isset($profile->location_ns)) { + $options['location_id'] = $profile->location_id; + $options['location_ns'] = $profile->location_ns; + } + } + + return $options; + } } -- cgit v1.2.3-54-g00ecf From 45c4078ca9de2f8f107e3c4a7cb759ac9cb2664a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 17:51:04 -0800 Subject: notices are immutable, use created date for updated --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index 7651d8bd5..0bb3b861c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1139,7 +1139,7 @@ class Notice extends Memcached_DataObject $xs->element('id', null, $this->uri); $xs->element('published', null, common_date_w3dtf($this->created)); - $xs->element('updated', null, common_date_w3dtf($this->modified)); + $xs->element('updated', null, common_date_w3dtf($this->created)); if ($this->reply_to) { $reply_notice = Notice::staticGet('id', $this->reply_to); -- cgit v1.2.3-54-g00ecf From e152bec2822a4ec773d02dd05f080a049ff3d524 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 29 Dec 2009 11:46:10 -0800 Subject: Fix for saving user location preferences -- user_id field was marked as an auto-increment and wasn't getting saved with new inserts. --- classes/statusnet.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 35a000aac..4077746c4 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -572,5 +572,5 @@ created = 142 modified = 384 [user_location_prefs__keys] -user_id = N +user_id = U -- cgit v1.2.3-54-g00ecf From 0fb114c34f1ad13683234762002dc9e98e16cc10 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 29 Dec 2009 11:46:10 -0800 Subject: Fix for saving user location preferences -- user_id field was marked as an auto-increment and wasn't getting saved with new inserts. --- classes/statusnet.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 35a000aac..4077746c4 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -572,5 +572,5 @@ created = 142 modified = 384 [user_location_prefs__keys] -user_id = N +user_id = U -- cgit v1.2.3-54-g00ecf From e3850e5273904a222580ff8daa3e778518721161 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 29 Dec 2009 14:05:43 -0800 Subject: Add progress output and optional --sleep-time parameter to triminboxes.php --- classes/Notice_inbox.php | 9 +++++++++ scripts/triminboxes.php | 24 ++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index b39006542..d3ddad656 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -106,6 +106,13 @@ class Notice_inbox extends Memcached_DataObject return Memcached_DataObject::pkeyGet('Notice_inbox', $kv); } + /** + * Trim inbox for a given user to latest NOTICE_INBOX_LIMIT items + * (up to NOTICE_INBOX_GC_MAX will be deleted). + * + * @param int $user_id + * @return int count of notices dropped from the inbox, if any + */ static function gc($user_id) { $entry = new Notice_inbox(); @@ -133,6 +140,8 @@ class Notice_inbox extends Memcached_DataObject $notices = array(); } } + + return $total; } static function deleteMatching($user_id, $notices) diff --git a/scripts/triminboxes.php b/scripts/triminboxes.php index da09817e5..ea4751305 100644 --- a/scripts/triminboxes.php +++ b/scripts/triminboxes.php @@ -21,19 +21,21 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); $shortoptions = 'u::'; -$longoptions = array('start-user-id::'); +$longoptions = array('start-user-id=', 'sleep-time='); $helptext = << --start-user-id= User ID to start after. Default is all. + --sleep-time= Amount of time to wait (in seconds) between trims. Default is zero. END_OF_TRIM_HELP; require_once INSTALLDIR.'/scripts/commandline.inc'; $id = null; +$sleep_time = 0; if (have_option('u')) { $id = get_option_value('u'); @@ -43,6 +45,12 @@ if (have_option('u')) { $id = null; } +if (have_option('--sleep-time')) { + $sleep_time = intval(get_option_value('--sleep-time')); +} + +$quiet = have_option('q') || have_option('--quiet'); + $user = new User(); if (!empty($id)) { @@ -52,5 +60,17 @@ if (!empty($id)) { $cnt = $user->find(); while ($user->fetch()) { - Notice_inbox::gc($user->id); + if (!$quiet) { + print "Trimming inbox for user $user->id"; + } + $count = Notice_inbox::gc($user->id); + if ($count) { + if (!$quiet) { + print ": $count trimmed..."; + } + sleep($sleep_time); + } + if (!$quiet) { + print "\n"; + } } -- cgit v1.2.3-54-g00ecf From 45c9d3d729a9c811282bdb9caa70450218200e8b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 29 Dec 2009 14:05:43 -0800 Subject: Add progress output and optional --sleep-time parameter to triminboxes.php --- classes/Notice_inbox.php | 9 +++++++++ scripts/triminboxes.php | 24 ++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index b39006542..d3ddad656 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -106,6 +106,13 @@ class Notice_inbox extends Memcached_DataObject return Memcached_DataObject::pkeyGet('Notice_inbox', $kv); } + /** + * Trim inbox for a given user to latest NOTICE_INBOX_LIMIT items + * (up to NOTICE_INBOX_GC_MAX will be deleted). + * + * @param int $user_id + * @return int count of notices dropped from the inbox, if any + */ static function gc($user_id) { $entry = new Notice_inbox(); @@ -133,6 +140,8 @@ class Notice_inbox extends Memcached_DataObject $notices = array(); } } + + return $total; } static function deleteMatching($user_id, $notices) diff --git a/scripts/triminboxes.php b/scripts/triminboxes.php index da09817e5..ea4751305 100644 --- a/scripts/triminboxes.php +++ b/scripts/triminboxes.php @@ -21,19 +21,21 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); $shortoptions = 'u::'; -$longoptions = array('start-user-id::'); +$longoptions = array('start-user-id=', 'sleep-time='); $helptext = << --start-user-id= User ID to start after. Default is all. + --sleep-time= Amount of time to wait (in seconds) between trims. Default is zero. END_OF_TRIM_HELP; require_once INSTALLDIR.'/scripts/commandline.inc'; $id = null; +$sleep_time = 0; if (have_option('u')) { $id = get_option_value('u'); @@ -43,6 +45,12 @@ if (have_option('u')) { $id = null; } +if (have_option('--sleep-time')) { + $sleep_time = intval(get_option_value('--sleep-time')); +} + +$quiet = have_option('q') || have_option('--quiet'); + $user = new User(); if (!empty($id)) { @@ -52,5 +60,17 @@ if (!empty($id)) { $cnt = $user->find(); while ($user->fetch()) { - Notice_inbox::gc($user->id); + if (!$quiet) { + print "Trimming inbox for user $user->id"; + } + $count = Notice_inbox::gc($user->id); + if ($count) { + if (!$quiet) { + print ": $count trimmed..."; + } + sleep($sleep_time); + } + if (!$quiet) { + print "\n"; + } } -- cgit v1.2.3-54-g00ecf From 544e884d30618224c317931c031175c0f6319849 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 30 Dec 2009 08:56:43 -1000 Subject: Add magic formula to keep DB_DataObject from treating location prefs pkey as autoincrement --- classes/User_location_prefs.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'classes') diff --git a/classes/User_location_prefs.php b/classes/User_location_prefs.php index 52cb254ba..bd6029f97 100644 --- a/classes/User_location_prefs.php +++ b/classes/User_location_prefs.php @@ -45,4 +45,9 @@ class User_location_prefs extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + function sequenceKey() + { + return array(false, false, false); + } } -- cgit v1.2.3-54-g00ecf From 9218cce3cdc824e2011bcdf250a08ca1698f5ea1 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 30 Dec 2009 15:55:15 -0800 Subject: subbug debug info to check on free ordering --- classes/Memcached_DataObject.php | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index d8b0db5a6..4efec06ab 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -31,11 +31,20 @@ class Memcached_DataObject extends DB_DataObject function __destruct() { + if (get_class($this) == 'Profile') + common_log(LOG_INFO, 'subbug: destructing result id ' . $this->_DB_resultid); $this->free(); if (method_exists('DB_DataObject', '__destruct')) { parent::__destruct(); } } + + function free() + { + if (get_class($this) == 'Profile') + common_log(LOG_INFO, 'subbug: freeing result id ' . $this->_DB_resultid); + parent::free(); + } function &staticGet($cls, $k, $v=null) { -- cgit v1.2.3-54-g00ecf From ff50c2b91d9fadaa9a4ede11785408408fc2d3c5 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 30 Dec 2009 16:40:59 -0800 Subject: Revert debugging code --- classes/Memcached_DataObject.php | 9 --------- lib/profilelist.php | 5 ----- 2 files changed, 14 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 4efec06ab..d8b0db5a6 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -31,20 +31,11 @@ class Memcached_DataObject extends DB_DataObject function __destruct() { - if (get_class($this) == 'Profile') - common_log(LOG_INFO, 'subbug: destructing result id ' . $this->_DB_resultid); $this->free(); if (method_exists('DB_DataObject', '__destruct')) { parent::__destruct(); } } - - function free() - { - if (get_class($this) == 'Profile') - common_log(LOG_INFO, 'subbug: freeing result id ' . $this->_DB_resultid); - parent::free(); - } function &staticGet($cls, $k, $v=null) { diff --git a/lib/profilelist.php b/lib/profilelist.php index ae875ac01..3412d41d1 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -86,21 +86,16 @@ class ProfileList extends Widget function showProfiles() { - $log = strtolower(get_class($this)) == 'subscriberslist' && $this->owner->nickname == 'petercook'; $cnt = 0; - if ($log) common_log(LOG_INFO, "subbug: starting with {$this->profile->N}"); while ($this->profile->fetch()) { $cnt++; if($cnt > PROFILES_PER_PAGE) { - if ($log) common_log(LOG_INFO, "subbug: breaking at $cnt"); break; } - if ($log) common_log(LOG_INFO, "subbug: showing at $cnt"); $pli = $this->newListItem($this->profile); $pli->show(); } - if ($log) common_log(LOG_INFO, "subbug: ended at $cnt"); return $cnt; } -- cgit v1.2.3-54-g00ecf From 89cca01259d71f3da961ef64def3647f86a01567 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 30 Dec 2009 16:42:57 -0800 Subject: Take Memcached_DataObject destructor back out to check whether it might be causing some under-the-hood problems. --- classes/Memcached_DataObject.php | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index d8b0db5a6..644b84d5c 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -23,20 +23,6 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; class Memcached_DataObject extends DB_DataObject { - /** - * Destructor to free global memory resources associated with - * this data object when it's unset or goes out of scope. - * DB_DataObject doesn't do this yet by itself. - */ - - function __destruct() - { - $this->free(); - if (method_exists('DB_DataObject', '__destruct')) { - parent::__destruct(); - } - } - function &staticGet($cls, $k, $v=null) { if (is_null($v)) { -- cgit v1.2.3-54-g00ecf From 727978332ae7e074024ac7f9900570ebb0e9ba80 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 1 Jan 2010 10:57:22 -1000 Subject: stop using DB_DataObject's staticGet() which caches --- classes/Memcached_DataObject.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index d8b0db5a6..f51133508 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -51,11 +51,17 @@ class Memcached_DataObject extends DB_DataObject if ($i) { return $i; } else { - $i = DB_DataObject::staticGet($cls, $k, $v); - if ($i) { + $i = DB_DataObject::factory($cls); + if (empty($i)) { + return null; + } + $result = $i->get($k, $v); + if ($result) { $i->encache(); + return $i; + } else { + return null; } - return $i; } } -- cgit v1.2.3-54-g00ecf From b0527801d9c2b84408bbfdf82bbdc5b778f72cfc Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 1 Jan 2010 11:02:56 -1000 Subject: add cleanup method to cleanup a single row --- classes/Memcached_DataObject.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index f51133508..cf7fb4340 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -253,6 +253,18 @@ class Memcached_DataObject extends DB_DataObject return new ArrayWrapper($cached); } + function cleanup() + { + global $_DB_DATAOBJECT; + + if (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) { + unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]); + } + if (isset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) { + unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]); + } + } + // We overload so that 'SET NAMES "utf8"' is called for // each connection -- cgit v1.2.3-54-g00ecf From 79c2e3f7202aa652414df885bd4c917a316ea7f3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 1 Jan 2010 11:27:13 -1000 Subject: Revert "add cleanup method to cleanup a single row" This reverts commit b0527801d9c2b84408bbfdf82bbdc5b778f72cfc. --- classes/Memcached_DataObject.php | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index cf7fb4340..f51133508 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -253,18 +253,6 @@ class Memcached_DataObject extends DB_DataObject return new ArrayWrapper($cached); } - function cleanup() - { - global $_DB_DATAOBJECT; - - if (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) { - unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]); - } - if (isset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) { - unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]); - } - } - // We overload so that 'SET NAMES "utf8"' is called for // each connection -- cgit v1.2.3-54-g00ecf From 52fbd101629b59f279195d0b11c7775b8aa4637f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 08:36:47 -1000 Subject: incorrectly used empty() instead of isset() for a variable that could be 0 --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index 0bb3b861c..93e94230d 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -214,7 +214,7 @@ class Notice extends Memcached_DataObject extract($options); } - if (empty($is_local)) { + if (!isset($is_local)) { $is_local = Notice::LOCAL_PUBLIC; } -- cgit v1.2.3-54-g00ecf From 2bd32dfad73d1387353199e5f45d02a9c5d770e5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 16:21:19 -1000 Subject: change harmless check of to check of in Memcached_DataObject --- classes/Memcached_DataObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index bf61b0766..ad8876ff9 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -99,7 +99,7 @@ class Memcached_DataObject extends DB_DataObject } static function cacheKey($cls, $k, $v) { - if (is_object($cls) || is_object($j) || is_object($v)) { + if (is_object($cls) || is_object($k) || is_object($v)) { $e = new Exception(); common_log(LOG_ERR, __METHOD__ . ' object in param: ' . str_replace("\n", " ", $e->getTraceAsString())); -- cgit v1.2.3-54-g00ecf From d32fb7c7c40e3d5fa67496d5df0574fc9c2e0151 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 16:28:46 -1000 Subject: return false from Memcached_DataObject::staticGet() on not found, like DB_DataObject --- classes/Memcached_DataObject.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index ad8876ff9..b43cb0b56 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -39,14 +39,14 @@ class Memcached_DataObject extends DB_DataObject } else { $i = DB_DataObject::factory($cls); if (empty($i)) { - return null; + return false; } $result = $i->get($k, $v); if ($result) { $i->encache(); return $i; } else { - return null; + return false; } } } -- cgit v1.2.3-54-g00ecf From ec380887f71a1eadc75bad0289f9a0dbee7f2913 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 3 Jan 2010 10:52:24 -1000 Subject: use keys() instead of keyTypes() so plugin data object work --- classes/Memcached_DataObject.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 1608720d1..b72c3d7b6 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -139,16 +139,6 @@ class Memcached_DataObject extends DB_DataObject } } - function keyTypes() - { - global $_DB_DATAOBJECT; - if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) { - $this->databaseStructure(); - - } - return $_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]; - } - function encache() { $c = $this->memcache(); @@ -157,7 +147,7 @@ class Memcached_DataObject extends DB_DataObject } else { $pkey = array(); $pval = array(); - $types = $this->keyTypes(); + $types = $this->keys(); ksort($types); foreach ($types as $key => $type) { if ($type == 'K') { @@ -182,7 +172,7 @@ class Memcached_DataObject extends DB_DataObject } else { $pkey = array(); $pval = array(); - $types = $this->keyTypes(); + $types = $this->keys(); ksort($types); foreach ($types as $key => $type) { if ($type == 'K') { -- cgit v1.2.3-54-g00ecf From d5fb88e1c0a617423a6fd9f9a23141c36245f38c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 3 Jan 2010 11:24:05 -1000 Subject: Revert "use keys() instead of keyTypes() so plugin data object work" This reverts commit ec380887f71a1eadc75bad0289f9a0dbee7f2913. --- classes/Memcached_DataObject.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index b72c3d7b6..1608720d1 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -139,6 +139,16 @@ class Memcached_DataObject extends DB_DataObject } } + function keyTypes() + { + global $_DB_DATAOBJECT; + if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) { + $this->databaseStructure(); + + } + return $_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]; + } + function encache() { $c = $this->memcache(); @@ -147,7 +157,7 @@ class Memcached_DataObject extends DB_DataObject } else { $pkey = array(); $pval = array(); - $types = $this->keys(); + $types = $this->keyTypes(); ksort($types); foreach ($types as $key => $type) { if ($type == 'K') { @@ -172,7 +182,7 @@ class Memcached_DataObject extends DB_DataObject } else { $pkey = array(); $pval = array(); - $types = $this->keys(); + $types = $this->keyTypes(); ksort($types); foreach ($types as $key => $type) { if ($type == 'K') { -- cgit v1.2.3-54-g00ecf From 8f362e9956ef699511344e0a494669ae78aa93eb Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 4 Jan 2010 08:53:28 -1000 Subject: user_id is a non-autoincrement pkey for user_location_prefs --- classes/statusnet.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 4077746c4..ac31148da 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -572,5 +572,5 @@ created = 142 modified = 384 [user_location_prefs__keys] -user_id = U +user_id = K -- cgit v1.2.3-54-g00ecf From 5a1ea0b9b28138bc4e06d96e2910b0cf3be1eab2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 4 Jan 2010 08:59:19 -1000 Subject: Stop caching unfindable keys There were some problems with the automated cache/uncache system for data objects that made us cache unfindable keys (with null attributes and sometimes null names). Fixed those problems and refactored the encache() and decache() methods so they use a helper to find the cache keys to use. --- classes/Memcached_DataObject.php | 83 ++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 33 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 1608720d1..020d813b2 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -152,52 +152,69 @@ class Memcached_DataObject extends DB_DataObject function encache() { $c = $this->memcache(); + if (!$c) { return false; - } else { - $pkey = array(); - $pval = array(); - $types = $this->keyTypes(); - ksort($types); - foreach ($types as $key => $type) { - if ($type == 'K') { - $pkey[] = $key; - $pval[] = $this->$key; - } else { - $c->set($this->cacheKey($this->tableName(), $key, $this->$key), $this); - } - } - # XXX: should work for both compound and scalar pkeys - $pvals = implode(',', $pval); - $pkeys = implode(',', $pkey); - $c->set($this->cacheKey($this->tableName(), $pkeys, $pvals), $this); + } + + $keys = $this->_allCacheKeys(); + + foreach ($keys as $key) { + $c->set($key, $this); } } function decache() { $c = $this->memcache(); + if (!$c) { return false; - } else { - $pkey = array(); - $pval = array(); - $types = $this->keyTypes(); - ksort($types); - foreach ($types as $key => $type) { - if ($type == 'K') { - $pkey[] = $key; - $pval[] = $this->$key; - } else { - $c->delete($this->cacheKey($this->tableName(), $key, $this->$key)); + } + + $keys = $this->_allCacheKeys(); + + foreach ($keys as $key) { + $c->delete($key, $this); + } + } + + function _allCacheKeys() + { + $ckeys = array(); + + $types = $this->keyTypes(); + ksort($types); + + $pkey = array(); + $pval = array(); + + foreach ($types as $key => $type) { + + assert(!empty($key)); + + if ($type == 'U') { + if (empty($this->$key)) { + continue; } + $ckeys[] = $this->cacheKey($this->tableName(), $key, $this->$key); + } else if ($type == 'K' || $type == 'N') { + $pkey[] = $key; + $pval[] = $this->$key; + } else { + throw new Exception("Unknown key type $key => $type for " . $this->tableName()); } - # should work for both compound and scalar pkeys - # XXX: comma works for now but may not be safe separator for future keys - $pvals = implode(',', $pval); - $pkeys = implode(',', $pkey); - $c->delete($this->cacheKey($this->tableName(), $pkeys, $pvals)); } + + assert(count($pkey) > 0); + + // XXX: should work for both compound and scalar pkeys + $pvals = implode(',', $pval); + $pkeys = implode(',', $pkey); + + $ckeys[] = $this->cacheKey($this->tableName(), $pkeys, $pvals); + + return $ckeys; } function multicache($cls, $kv) -- cgit v1.2.3-54-g00ecf From abc9b332412921e7ae7f730b23e186bcba412486 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 4 Jan 2010 10:00:17 -1000 Subject: Memcached_DataObject stores empty values in the cache There's great value in knowing that something doesn't exist. We now cache this information, and carefully compare the results from cache as $results !== false instead of !empty($results), since some empty values (null, 0, empty array, empty string) are stored in the cache. Caching staticGet() and pkeyGet() now store DB misses in the cache, and cachedQuery() checks for empty results from the cache. --- classes/Memcached_DataObject.php | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 020d813b2..a77e43d38 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -19,8 +19,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; - class Memcached_DataObject extends DB_DataObject { /** @@ -57,7 +55,7 @@ class Memcached_DataObject extends DB_DataObject unset($i); } $i = Memcached_DataObject::getcached($cls, $k, $v); - if ($i) { + if ($i !== false) { // false == cache miss return $i; } else { $i = DB_DataObject::factory($cls); @@ -69,6 +67,12 @@ class Memcached_DataObject extends DB_DataObject $i->encache(); return $i; } else { + // save the fact that no such row exists + $c = self::memcache(); + if (!empty($c)) { + $ck = self::cachekey($cls, $k, $v); + $c->set($ck, null); + } return false; } } @@ -77,10 +81,13 @@ class Memcached_DataObject extends DB_DataObject function &pkeyGet($cls, $kv) { $i = Memcached_DataObject::multicache($cls, $kv); - if ($i) { + if ($i !== false) { // false == cache miss return $i; } else { - $i = new $cls(); + $i = DB_DataObject::factory($cls); + if (empty($i)) { + return false; + } foreach ($kv as $k => $v) { $i->$k = $v; } @@ -88,6 +95,11 @@ class Memcached_DataObject extends DB_DataObject $i->encache(); } else { $i = null; + $c = self::memcache(); + if (!empty($c)) { + $ck = self::multicacheKey($cls, $kv); + $c->set($ck, null); + } } return $i; } @@ -220,16 +232,22 @@ class Memcached_DataObject extends DB_DataObject function multicache($cls, $kv) { ksort($kv); - $c = Memcached_DataObject::memcache(); + $c = self::memcache(); if (!$c) { return false; } else { - $pkeys = implode(',', array_keys($kv)); - $pvals = implode(',', array_values($kv)); - return $c->get(Memcached_DataObject::cacheKey($cls, $pkeys, $pvals)); + return $c->get(self::multicacheKey($cls, $kv)); } } + static function multicacheKey($cls, $kv) + { + ksort($kv); + $pkeys = implode(',', array_keys($kv)); + $pvals = implode(',', array_values($kv)); + return self::cacheKey($cls, $pkeys, $pvals); + } + function getSearchEngine($table) { require_once INSTALLDIR.'/lib/search_engines.php'; @@ -264,7 +282,8 @@ class Memcached_DataObject extends DB_DataObject $key_part = common_keyize($cls).':'.md5($qry); $ckey = common_cache_key($key_part); $stored = $c->get($ckey); - if ($stored) { + + if ($stored !== false) { return new ArrayWrapper($stored); } -- cgit v1.2.3-54-g00ecf From 254ea279d8c86ed25ed74bff036b16e6293571f7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 4 Jan 2010 10:02:59 -1000 Subject: carefully compare cached settings against false for Config --- classes/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Config.php b/classes/Config.php index 390d75381..6d914ca1f 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -59,7 +59,7 @@ class Config extends Memcached_DataObject if (!empty($c)) { $settings = $c->get(common_cache_key(self::settingsKey)); - if (!empty($settings)) { + if ($settings !== false) { return $settings; } } -- cgit v1.2.3-54-g00ecf From 06b6a27d7d31cb0680dffff70c498e27ece56762 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 4 Jan 2010 10:03:57 -1000 Subject: cached id streams can be empty, compare against false --- classes/Notice.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index 3e55bd6fa..e8bc509a6 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1207,7 +1207,7 @@ class Notice extends Memcached_DataObject $idstr = $cache->get($idkey); - if (!empty($idstr)) { + if ($idstr !== false) { // Cache hit! Woohoo! $window = explode(',', $idstr); $ids = array_slice($window, $offset, $limit); @@ -1216,7 +1216,7 @@ class Notice extends Memcached_DataObject $laststr = $cache->get($idkey.';last'); - if (!empty($laststr)) { + if ($laststr !== false) { $window = explode(',', $laststr); $last_id = $window[0]; $new_ids = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW, @@ -1376,7 +1376,7 @@ class Notice extends Memcached_DataObject $ids = $this->_repeatStreamDirect($limit); } else { $idstr = $cache->get(common_cache_key('notice:repeats:'.$this->id)); - if (!empty($idstr)) { + if ($idstr !== false) { $ids = explode(',', $idstr); } else { $ids = $this->_repeatStreamDirect(100); -- cgit v1.2.3-54-g00ecf From 440b9957f9ae6fdfdb44c39074803fcdbc64112d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 4 Jan 2010 14:24:16 -0800 Subject: Exclude process-specific link & result cache references from serialized Memcached_Data_Object instances. Should fix seemingly-random bugs due to destructor free()ing local resources by mistake. --- classes/Memcached_DataObject.php | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index a77e43d38..d830884b6 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -21,7 +21,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } class Memcached_DataObject extends DB_DataObject { - /** + /** * Destructor to free global memory resources associated with * this data object when it's unset or goes out of scope. * DB_DataObject doesn't do this yet by itself. @@ -35,6 +35,42 @@ class Memcached_DataObject extends DB_DataObject } } + /** + * Magic function called at serialize() time. + * + * We use this to drop a couple process-specific references + * from DB_DataObject which can cause trouble in future + * processes. + * + * @return array of variable names to include in serialization. + */ + function __sleep() + { + $vars = array_keys(get_object_vars($this)); + $skip = array('_DB_resultid', '_link_loaded'); + return array_diff($vars, $skip); + } + + /** + * Magic function called at unserialize() time. + * + * Clean out some process-specific variables which might + * be floating around from a previous process's cached + * objects. + * + * Old cached objects may still have them. + */ + function __wakeup() + { + // Refers to global state info from a previous process. + // Clear this out so we don't accidentally break global + // state in *this* process. + $this->_DB_resultid = null; + + // We don't have any local DBO refs, so clear these out. + $this->_link_loaded = false; + } + /** * Wrapper for DB_DataObject's static lookup using memcached * as backing instead of an in-process cache array. -- cgit v1.2.3-54-g00ecf From 8f02379f6e05e4bf1bff69d6d0fcf3d90a4d1181 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 4 Jan 2010 14:37:39 -0800 Subject: Revert "Take Memcached_DataObject destructor back out to check whether it might be causing some under-the-hood problems." This reverts commit 89cca01259d71f3da961ef64def3647f86a01567. --- classes/Memcached_DataObject.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index b43cb0b56..d89a9421e 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -23,6 +23,20 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; class Memcached_DataObject extends DB_DataObject { + /** + * Destructor to free global memory resources associated with + * this data object when it's unset or goes out of scope. + * DB_DataObject doesn't do this yet by itself. + */ + + function __destruct() + { + $this->free(); + if (method_exists('DB_DataObject', '__destruct')) { + parent::__destruct(); + } + } + function &staticGet($cls, $k, $v=null) { if (is_null($v)) { -- cgit v1.2.3-54-g00ecf From 78214c4e067616828478d600d500b34b6fcb9061 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 4 Jan 2010 14:38:56 -0800 Subject: Exclude process-specific link & result cache references from serialized Memcached_Data_Object instances. Should fix seemingly-random bugs due to destructor free()ing local resources by mistake. cherry-pick from 0.9.x --- classes/Memcached_DataObject.php | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index d89a9421e..ca360d411 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -37,6 +37,51 @@ class Memcached_DataObject extends DB_DataObject } } + /** + * Magic function called at serialize() time. + * + * We use this to drop a couple process-specific references + * from DB_DataObject which can cause trouble in future + * processes. + * + * @return array of variable names to include in serialization. + */ + function __sleep() + { + $vars = array_keys(get_object_vars($this)); + $skip = array('_DB_resultid', '_link_loaded'); + return array_diff($vars, $skip); + } + + /** + * Magic function called at unserialize() time. + * + * Clean out some process-specific variables which might + * be floating around from a previous process's cached + * objects. + * + * Old cached objects may still have them. + */ + function __wakeup() + { + // Refers to global state info from a previous process. + // Clear this out so we don't accidentally break global + // state in *this* process. + $this->_DB_resultid = null; + + // We don't have any local DBO refs, so clear these out. + $this->_link_loaded = false; + } + + /** + * Wrapper for DB_DataObject's static lookup using memcached + * as backing instead of an in-process cache array. + * + * @param string $cls classname of object type to load + * @param mixed $k key field name, or value for primary key + * @param mixed $v key field value, or leave out for primary key lookup + * @return mixed Memcached_DataObject subtype or false + */ function &staticGet($cls, $k, $v=null) { if (is_null($v)) { -- cgit v1.2.3-54-g00ecf From 9e2e0605ed6280daa4d74c4b962e4630d1078d90 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 5 Jan 2010 13:56:22 -0500 Subject: Move Authorization and Authentication plugin structures into core, instead of as plugins. This move makes sense as you can addPlugin('Authentication') for example - these are abstract classes designed to be implemented, not used directly. --- classes/User_username.php | 61 ++++++ lib/authenticationplugin.php | 231 ++++++++++++++++++++ lib/authorizationplugin.php | 105 +++++++++ plugins/Authentication/AuthenticationPlugin.php | 243 --------------------- plugins/Authentication/User_username.php | 61 ------ plugins/Authorization/AuthorizationPlugin.php | 108 --------- .../CasAuthentication/CasAuthenticationPlugin.php | 1 - .../LdapAuthenticationPlugin.php | 1 - .../LdapAuthorization/LdapAuthorizationPlugin.php | 1 - .../ReverseUsernameAuthenticationPlugin.php | 2 - 10 files changed, 397 insertions(+), 417 deletions(-) create mode 100644 classes/User_username.php create mode 100644 lib/authenticationplugin.php create mode 100644 lib/authorizationplugin.php delete mode 100644 plugins/Authentication/AuthenticationPlugin.php delete mode 100644 plugins/Authentication/User_username.php delete mode 100644 plugins/Authorization/AuthorizationPlugin.php (limited to 'classes') diff --git a/classes/User_username.php b/classes/User_username.php new file mode 100644 index 000000000..853fd5cb8 --- /dev/null +++ b/classes/User_username.php @@ -0,0 +1,61 @@ +user_id = $user->id; + $user_username->provider_name = $provider_name; + $user_username->username = $username; + $user_username->created = DB_DataObject_Cast::dateTime(); + if($user_username->insert()){ + return $user_username; + }else{ + return false; + } + } + + function table() { + return array( + 'user_id' => DB_DATAOBJECT_INT, + 'username' => DB_DATAOBJECT_STR, + 'provider_name' => DB_DATAOBJECT_STR , + 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + ); + } + + // now define the keys. + function keys() { + return array('provider_name', 'username'); + } + +} diff --git a/lib/authenticationplugin.php b/lib/authenticationplugin.php new file mode 100644 index 000000000..de479a576 --- /dev/null +++ b/lib/authenticationplugin.php @@ -0,0 +1,231 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Superclass for plugins that do authentication + * + * @category Plugin + * @package StatusNet + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +abstract class AuthenticationPlugin extends Plugin +{ + //is this plugin authoritative for authentication? + public $authoritative = false; + + //should accounts be automatically created after a successful login attempt? + public $autoregistration = false; + + //can the user change their email address + public $password_changeable=true; + + //unique name for this authentication provider + public $provider_name; + + //------------Auth plugin should implement some (or all) of these methods------------\\ + /** + * Check if a nickname/password combination is valid + * @param username + * @param password + * @return boolean true if the credentials are valid, false if they are invalid. + */ + function checkPassword($username, $password) + { + return false; + } + + /** + * Automatically register a user when they attempt to login with valid credentials. + * User::register($data) is a very useful method for this implementation + * @param username + * @return mixed instance of User, or false (if user couldn't be created) + */ + function autoRegister($username) + { + $registration_data = array(); + $registration_data['nickname'] = $username ; + return User::register($registration_data); + } + + /** + * Change a user's password + * The old password has been verified to be valid by this plugin before this call is made + * @param username + * @param oldpassword + * @param newpassword + * @return boolean true if the password was changed, false if password changing failed for some reason + */ + function changePassword($username,$oldpassword,$newpassword) + { + return false; + } + + //------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\ + function onInitializePlugin(){ + if(!isset($this->provider_name)){ + throw new Exception("must specify a provider_name for this authentication provider"); + } + } + + /** + * Internal AutoRegister event handler + * @param nickname + * @param provider_name + * @param user - the newly registered user + */ + function onAutoRegister($nickname, $provider_name, &$user) + { + if($provider_name == $this->provider_name && $this->autoregistration){ + $user = $this->autoregister($nickname); + if($user){ + User_username::register($user,$nickname,$this->provider_name); + return false; + } + } + } + + function onStartCheckPassword($nickname, $password, &$authenticatedUser){ + //map the nickname to a username + $user_username = new User_username(); + $user_username->username=$nickname; + $user_username->provider_name=$this->provider_name; + if($user_username->find() && $user_username->fetch()){ + $username = $user_username->username; + $authenticated = $this->checkPassword($username, $password); + if($authenticated){ + $authenticatedUser = User::staticGet('id', $user_username->user_id); + return false; + } + }else{ + $user = User::staticGet('nickname', $nickname); + if($user){ + //make sure a different provider isn't handling this nickname + $user_username = new User_username(); + $user_username->username=$nickname; + if(!$user_username->find()){ + //no other provider claims this username, so it's safe for us to handle it + $authenticated = $this->checkPassword($nickname, $password); + if($authenticated){ + $authenticatedUser = User::staticGet('nickname', $nickname); + User_username::register($authenticatedUser,$nickname,$this->provider_name); + return false; + } + } + }else{ + $authenticated = $this->checkPassword($nickname, $password); + if($authenticated){ + if(! Event::handle('AutoRegister', array($nickname, $this->provider_name, &$authenticatedUser))){ + //unlike most Event::handle lines of code, this one has a ! (not) + //we want to do this if the event *was* handled - this isn't a "default" implementation + //like most code of this form. + if($authenticatedUser){ + return false; + } + } + } + } + } + if($this->authoritative){ + return false; + }else{ + //we're not authoritative, so let other handlers try + return; + } + } + + function onStartChangePassword($user,$oldpassword,$newpassword) + { + if($this->password_changeable){ + $user_username = new User_username(); + $user_username->user_id=$user->id; + $user_username->provider_name=$this->provider_name; + if($user_username->find() && $user_username->fetch()){ + $authenticated = $this->checkPassword($user_username->username, $oldpassword); + if($authenticated){ + $result = $this->changePassword($user_username->username,$oldpassword,$newpassword); + if($result){ + //stop handling of other handlers, because what was requested was done + return false; + }else{ + throw new Exception(_('Password changing failed')); + } + }else{ + if($this->authoritative){ + //since we're authoritative, no other plugin could do this + throw new Exception(_('Password changing failed')); + }else{ + //let another handler try + return null; + } + } + } + }else{ + if($this->authoritative){ + //since we're authoritative, no other plugin could do this + throw new Exception(_('Password changing is not allowed')); + } + } + } + + function onStartAccountSettingsPasswordMenuItem($widget) + { + if($this->authoritative && !$this->password_changeable){ + //since we're authoritative, no other plugin could change passwords, so do not render the menu item + return false; + } + } + + function onCheckSchema() { + $schema = Schema::get(); + $schema->ensureTable('user_username', + array(new ColumnDef('provider_name', 'varchar', + '255', false, 'PRI'), + new ColumnDef('username', 'varchar', + '255', false, 'PRI'), + new ColumnDef('user_id', 'integer', + null, false), + new ColumnDef('created', 'datetime', + null, false), + new ColumnDef('modified', 'timestamp'))); + return true; + } + + function onUserDeleteRelated($user, &$tables) + { + $tables[] = 'User_username'; + return true; + } +} + diff --git a/lib/authorizationplugin.php b/lib/authorizationplugin.php new file mode 100644 index 000000000..733b0c065 --- /dev/null +++ b/lib/authorizationplugin.php @@ -0,0 +1,105 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Superclass for plugins that do authorization + * + * @category Plugin + * @package StatusNet + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +abstract class AuthorizationPlugin extends Plugin +{ + //is this plugin authoritative for authorization? + public $authoritative = false; + + //------------Auth plugin should implement some (or all) of these methods------------\\ + + /** + * Is a user allowed to log in? + * @param user + * @return boolean true if the user is allowed to login, false if explicitly not allowed to login, null if we don't explicitly allow or deny login + */ + function loginAllowed($user) { + return null; + } + + /** + * Does a profile grant the user a named role? + * @param profile + * @return boolean true if the profile has the role, false if not + */ + function hasRole($profile, $name) { + return false; + } + + //------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\ + + function onStartSetUser(&$user) { + $loginAllowed = $this->loginAllowed($user); + if($loginAllowed === true){ + return; + }else if($loginAllowed === false){ + $user = null; + return false; + }else{ + if($this->authoritative) { + $user = null; + return false; + }else{ + return; + } + } + } + + function onStartSetApiUser(&$user) { + return $this->onStartSetUser(&$user); + } + + function onStartHasRole($profile, $name, &$has_role) { + if($this->hasRole($profile, $name)){ + $has_role = true; + return false; + }else{ + if($this->authoritative) { + $has_role = false; + return false; + }else{ + return; + } + } + } +} + diff --git a/plugins/Authentication/AuthenticationPlugin.php b/plugins/Authentication/AuthenticationPlugin.php deleted file mode 100644 index 07f14035d..000000000 --- a/plugins/Authentication/AuthenticationPlugin.php +++ /dev/null @@ -1,243 +0,0 @@ -. - * - * @category Plugin - * @package StatusNet - * @author Craig Andrews - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Superclass for plugins that do authentication - * - * @category Plugin - * @package StatusNet - * @author Craig Andrews - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -abstract class AuthenticationPlugin extends Plugin -{ - //is this plugin authoritative for authentication? - public $authoritative = false; - - //should accounts be automatically created after a successful login attempt? - public $autoregistration = false; - - //can the user change their email address - public $password_changeable=true; - - //unique name for this authentication provider - public $provider_name; - - //------------Auth plugin should implement some (or all) of these methods------------\\ - /** - * Check if a nickname/password combination is valid - * @param username - * @param password - * @return boolean true if the credentials are valid, false if they are invalid. - */ - function checkPassword($username, $password) - { - return false; - } - - /** - * Automatically register a user when they attempt to login with valid credentials. - * User::register($data) is a very useful method for this implementation - * @param username - * @return mixed instance of User, or false (if user couldn't be created) - */ - function autoRegister($username) - { - $registration_data = array(); - $registration_data['nickname'] = $username ; - return User::register($registration_data); - } - - /** - * Change a user's password - * The old password has been verified to be valid by this plugin before this call is made - * @param username - * @param oldpassword - * @param newpassword - * @return boolean true if the password was changed, false if password changing failed for some reason - */ - function changePassword($username,$oldpassword,$newpassword) - { - return false; - } - - //------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\ - function onInitializePlugin(){ - if(!isset($this->provider_name)){ - throw new Exception("must specify a provider_name for this authentication provider"); - } - } - - /** - * Internal AutoRegister event handler - * @param nickname - * @param provider_name - * @param user - the newly registered user - */ - function onAutoRegister($nickname, $provider_name, &$user) - { - if($provider_name == $this->provider_name && $this->autoregistration){ - $user = $this->autoregister($nickname); - if($user){ - User_username::register($user,$nickname,$this->provider_name); - return false; - } - } - } - - function onStartCheckPassword($nickname, $password, &$authenticatedUser){ - //map the nickname to a username - $user_username = new User_username(); - $user_username->username=$nickname; - $user_username->provider_name=$this->provider_name; - if($user_username->find() && $user_username->fetch()){ - $username = $user_username->username; - $authenticated = $this->checkPassword($username, $password); - if($authenticated){ - $authenticatedUser = User::staticGet('id', $user_username->user_id); - return false; - } - }else{ - $user = User::staticGet('nickname', $nickname); - if($user){ - //make sure a different provider isn't handling this nickname - $user_username = new User_username(); - $user_username->username=$nickname; - if(!$user_username->find()){ - //no other provider claims this username, so it's safe for us to handle it - $authenticated = $this->checkPassword($nickname, $password); - if($authenticated){ - $authenticatedUser = User::staticGet('nickname', $nickname); - User_username::register($authenticatedUser,$nickname,$this->provider_name); - return false; - } - } - }else{ - $authenticated = $this->checkPassword($nickname, $password); - if($authenticated){ - if(! Event::handle('AutoRegister', array($nickname, $this->provider_name, &$authenticatedUser))){ - //unlike most Event::handle lines of code, this one has a ! (not) - //we want to do this if the event *was* handled - this isn't a "default" implementation - //like most code of this form. - if($authenticatedUser){ - return false; - } - } - } - } - } - if($this->authoritative){ - return false; - }else{ - //we're not authoritative, so let other handlers try - return; - } - } - - function onStartChangePassword($user,$oldpassword,$newpassword) - { - if($this->password_changeable){ - $user_username = new User_username(); - $user_username->user_id=$user->id; - $user_username->provider_name=$this->provider_name; - if($user_username->find() && $user_username->fetch()){ - $authenticated = $this->checkPassword($user_username->username, $oldpassword); - if($authenticated){ - $result = $this->changePassword($user_username->username,$oldpassword,$newpassword); - if($result){ - //stop handling of other handlers, because what was requested was done - return false; - }else{ - throw new Exception(_('Password changing failed')); - } - }else{ - if($this->authoritative){ - //since we're authoritative, no other plugin could do this - throw new Exception(_('Password changing failed')); - }else{ - //let another handler try - return null; - } - } - } - }else{ - if($this->authoritative){ - //since we're authoritative, no other plugin could do this - throw new Exception(_('Password changing is not allowed')); - } - } - } - - function onStartAccountSettingsPasswordMenuItem($widget) - { - if($this->authoritative && !$this->password_changeable){ - //since we're authoritative, no other plugin could change passwords, so do not render the menu item - return false; - } - } - - function onAutoload($cls) - { - switch ($cls) - { - case 'User_username': - require_once(INSTALLDIR.'/plugins/Authentication/User_username.php'); - return false; - default: - return true; - } - } - - function onCheckSchema() { - $schema = Schema::get(); - $schema->ensureTable('user_username', - array(new ColumnDef('provider_name', 'varchar', - '255', false, 'PRI'), - new ColumnDef('username', 'varchar', - '255', false, 'PRI'), - new ColumnDef('user_id', 'integer', - null, false), - new ColumnDef('created', 'datetime', - null, false), - new ColumnDef('modified', 'timestamp'))); - return true; - } - - function onUserDeleteRelated($user, &$tables) - { - $tables[] = 'User_username'; - return true; - } -} - diff --git a/plugins/Authentication/User_username.php b/plugins/Authentication/User_username.php deleted file mode 100644 index 853fd5cb8..000000000 --- a/plugins/Authentication/User_username.php +++ /dev/null @@ -1,61 +0,0 @@ -user_id = $user->id; - $user_username->provider_name = $provider_name; - $user_username->username = $username; - $user_username->created = DB_DataObject_Cast::dateTime(); - if($user_username->insert()){ - return $user_username; - }else{ - return false; - } - } - - function table() { - return array( - 'user_id' => DB_DATAOBJECT_INT, - 'username' => DB_DATAOBJECT_STR, - 'provider_name' => DB_DATAOBJECT_STR , - 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME - ); - } - - // now define the keys. - function keys() { - return array('provider_name', 'username'); - } - -} diff --git a/plugins/Authorization/AuthorizationPlugin.php b/plugins/Authorization/AuthorizationPlugin.php deleted file mode 100644 index e4e046d08..000000000 --- a/plugins/Authorization/AuthorizationPlugin.php +++ /dev/null @@ -1,108 +0,0 @@ -. - * - * @category Plugin - * @package StatusNet - * @author Craig Andrews - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Superclass for plugins that do authorization - * - * @category Plugin - * @package StatusNet - * @author Craig Andrews - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -abstract class AuthorizationPlugin extends Plugin -{ - //is this plugin authoritative for authorization? - public $authoritative = false; - - //------------Auth plugin should implement some (or all) of these methods------------\\ - - /** - * Is a user allowed to log in? - * @param user - * @return boolean true if the user is allowed to login, false if explicitly not allowed to login, null if we don't explicitly allow or deny login - */ - function loginAllowed($user) { - return null; - } - - /** - * Does a profile grant the user a named role? - * @param profile - * @return boolean true if the profile has the role, false if not - */ - function hasRole($profile, $name) { - return false; - } - - //------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\ - function onInitializePlugin(){ - - } - - function onStartSetUser(&$user) { - $loginAllowed = $this->loginAllowed($user); - if($loginAllowed === true){ - return; - }else if($loginAllowed === false){ - $user = null; - return false; - }else{ - if($this->authoritative) { - $user = null; - return false; - }else{ - return; - } - } - } - - function onStartSetApiUser(&$user) { - return $this->onStartSetUser(&$user); - } - - function onStartHasRole($profile, $name, &$has_role) { - if($this->hasRole($profile, $name)){ - $has_role = true; - return false; - }else{ - if($this->authoritative) { - $has_role = false; - return false; - }else{ - return; - } - } - } -} - diff --git a/plugins/CasAuthentication/CasAuthenticationPlugin.php b/plugins/CasAuthentication/CasAuthenticationPlugin.php index 8f29c7d2a..26f21af16 100644 --- a/plugins/CasAuthentication/CasAuthenticationPlugin.php +++ b/plugins/CasAuthentication/CasAuthenticationPlugin.php @@ -34,7 +34,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { // We bundle the phpCAS library... set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/CAS'); -require_once INSTALLDIR.'/plugins/Authentication/AuthenticationPlugin.php'; class CasAuthenticationPlugin extends AuthenticationPlugin { public $server; diff --git a/plugins/LdapAuthentication/LdapAuthenticationPlugin.php b/plugins/LdapAuthentication/LdapAuthenticationPlugin.php index 39967fe42..af42be761 100644 --- a/plugins/LdapAuthentication/LdapAuthenticationPlugin.php +++ b/plugins/LdapAuthentication/LdapAuthenticationPlugin.php @@ -31,7 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/plugins/Authentication/AuthenticationPlugin.php'; require_once 'Net/LDAP2.php'; class LdapAuthenticationPlugin extends AuthenticationPlugin diff --git a/plugins/LdapAuthorization/LdapAuthorizationPlugin.php b/plugins/LdapAuthorization/LdapAuthorizationPlugin.php index 5e759c379..7673e61ef 100644 --- a/plugins/LdapAuthorization/LdapAuthorizationPlugin.php +++ b/plugins/LdapAuthorization/LdapAuthorizationPlugin.php @@ -31,7 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/plugins/Authorization/AuthorizationPlugin.php'; require_once 'Net/LDAP2.php'; class LdapAuthorizationPlugin extends AuthorizationPlugin diff --git a/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php b/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php index d48283b2e..d157ea067 100644 --- a/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php +++ b/plugins/ReverseUsernameAuthentication/ReverseUsernameAuthenticationPlugin.php @@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/plugins/Authentication/AuthenticationPlugin.php'; - class ReverseUsernameAuthenticationPlugin extends AuthenticationPlugin { //---interface implementation---// -- cgit v1.2.3-54-g00ecf From 250bcfa8dc3ebf3c2c8458f363a62c529eb3a7f6 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 5 Jan 2010 17:47:37 -0500 Subject: Require users to login to view attachments on private sites Thank you jeff-themovie for this implementation! --- README | 20 ++++++++++++---- actions/getfile.php | 66 ++++++++++++++++++++++++++++++++++++++--------------- classes/File.php | 33 ++++++++++++++++----------- config.php.sample | 17 +++++++++++++- htaccess.sample | 8 ------- lib/default.php | 1 + 6 files changed, 100 insertions(+), 45 deletions(-) (limited to 'classes') diff --git a/README b/README index 6e39890cb..c26fe786e 100644 --- a/README +++ b/README @@ -710,11 +710,21 @@ private site, but users of the private site may be able to subscribe to users on a remote site. (Or not... it's not well tested.) The "proper behaviour" hasn't been defined here, so handle with care. -If fancy URLs is enabled, access to file attachments can also be -restricted to logged-in users only. Uncomment the appropriate rewrite -rule in .htaccess or your server's httpd.conf. (This most likely will -not work if you are using a virtual server for attachments, so consider -the performance/security tradeoff.) +Access to file attachments can also be restricted to logged-in users only. +1. Add a directory outside the web root where your file uploads will be + stored. Usually a command like this will work: + + mkdir /var/www/mublog-files + +2. Make the file uploads directory writeable by the web server. An + insecure way to do this is: + + chmod a+x /var/www/mublog-files + +3. Tell StatusNet to use this directory for file uploads. Add a line + like this to your config.php: + + $config['attachments']['dir'] = '/var/www/mublog-files'; Upgrading ========= diff --git a/actions/getfile.php b/actions/getfile.php index ecda34c0f..cd327e410 100644 --- a/actions/getfile.php +++ b/actions/getfile.php @@ -1,13 +1,13 @@ . * - * @category Personal + * @category PrivateAttachments * @package StatusNet * @author Jeffery To - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { +if (!defined('STATUSNET')) { exit(1); } require_once 'MIME/Type.php'; /** - * Action for getting a file attachment + * An action for returning a requested file * - * @category Personal - * @package StatusNet - * @author Jeffery To - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ + * The StatusNet system will do an implicit user check if the site is + * private before allowing this to continue + * + * @category PrivateAttachments + * @package StatusNet + * @author Jeffery To + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ */ class GetfileAction extends Action @@ -68,7 +72,7 @@ class GetfileAction extends Action $path = null; if ($filename) { - $path = common_config('attachments', 'dir') . $filename; + $path = File::path($filename); } if (empty($path) or !file_exists($path)) { @@ -103,6 +107,10 @@ class GetfileAction extends Action function lastModified() { + if (common_config('site', 'use_x_sendfile')) { + return null; + } + return filemtime($this->path); } @@ -114,8 +122,24 @@ class GetfileAction extends Action * * @return string etag http header */ + function etag() { + if (common_config('site', 'use_x_sendfile')) { + return null; + } + + $cache = common_memcache(); + if($cache) { + $key = common_cache_key('attachments:etag:' . $this->path); + $etag = $cache->get($key); + if($etag === false) { + $etag = crc32(file_get_contents($this->path)); + $cache->set($key,$etag); + } + return $etag; + } + $stat = stat($this->path); return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"'; } @@ -133,13 +157,19 @@ class GetfileAction extends Action // undo headers set by PHP sessions $sec = session_cache_expire() * 60; header('Expires: ' . date(DATE_RFC1123, time() + $sec)); - header('Cache-Control: public, max-age=' . $sec); - header('Pragma: public'); + header('Cache-Control: max-age=' . $sec); parent::handle($args); $path = $this->path; + header('Content-Type: ' . MIME_Type::autoDetect($path)); - readfile($path); + + if (common_config('site', 'use_x_sendfile')) { + header('X-Sendfile: ' . $path); + } else { + header('Content-Length: ' . filesize($path)); + readfile($path); + } } } diff --git a/classes/File.php b/classes/File.php index e04a9d525..6173f31d6 100644 --- a/classes/File.php +++ b/classes/File.php @@ -182,25 +182,32 @@ class File extends Memcached_DataObject static function url($filename) { - $path = common_config('attachments', 'path'); + if(common_config('site','private')) { - if ($path[strlen($path)-1] != '/') { - $path .= '/'; - } + return common_local_url('getfile', + array('filename' => $filename)); - if ($path[0] != '/') { - $path = '/'.$path; - } + } else { + $path = common_config('attachments', 'path'); - $server = common_config('attachments', 'server'); + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } - if (empty($server)) { - $server = common_config('site', 'server'); - } + if ($path[0] != '/') { + $path = '/'.$path; + } + + $server = common_config('attachments', 'server'); - // XXX: protocol + if (empty($server)) { + $server = common_config('site', 'server'); + } - return 'http://'.$server.$path.$filename; + // XXX: protocol + + return 'http://'.$server.$path.$filename; + } } function getEnclosure(){ diff --git a/config.php.sample b/config.php.sample index 91e6614c0..b8852dc67 100644 --- a/config.php.sample +++ b/config.php.sample @@ -41,6 +41,20 @@ $config['site']['path'] = 'statusnet'; // Make the site invisible to non-logged-in users // $config['site']['private'] = true; +// If your web server supports X-Sendfile (Apache with mod_xsendfile, +// lighttpd, nginx), you can enable X-Sendfile support for better +// performance. Presently, only attachment serving when the site is +// in private mode will use X-Sendfile. +// $config['site']['X-Sendfile'] = false; +// You may also need to enable X-Sendfile support for your web server and +// allow it to access files outside of the web root. For Apache with +// mod_xsendfile, you can add these to your .htaccess or server config: +// +// XSendFile on +// XSendFileAllowAbove on +// +// See http://tn123.ath.cx/mod_xsendfile/ for mod_xsendfile. + // If you want logging sent to a file instead of syslog // $config['site']['logfile'] = '/tmp/statusnet.log'; @@ -265,6 +279,7 @@ $config['sphinx']['port'] = 3312; // $config['attachments']['user_quota'] = 50000000; // $config['attachments']['monthly_quota'] = 15000000; // $config['attachments']['uploads'] = true; -// $config['attachments']['path'] = "/file/"; +// $config['attachments']['path'] = "/file/"; //ignored if site is private +// $config['attachments']['dir'] = INSTALLDIR . '/file/'; // $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/'; diff --git a/htaccess.sample b/htaccess.sample index 91ae9da9b..37eb8e01e 100644 --- a/htaccess.sample +++ b/htaccess.sample @@ -5,14 +5,6 @@ RewriteBase /mublog/ - # If your site is private and want to only allow logged-in users to - # be able to download file attachments, uncomment this rule. - # - # If you have a custom attachment path - # ($config['attachments']['path']), change "file/" to match. - # - #RewriteRule ^file/(.*) getfile/$1 - RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.*) index.php?p=$1 [L,QSA] diff --git a/lib/default.php b/lib/default.php index eea11eb2b..f2e577149 100644 --- a/lib/default.php +++ b/lib/default.php @@ -54,6 +54,7 @@ $default = 'dupelimit' => 60, # default for same person saying the same thing 'textlimit' => 140, 'indent' => true, + 'use_x_sendfile' => false, ), 'db' => array('database' => 'YOU HAVE TO SET THIS IN config.php', -- cgit v1.2.3-54-g00ecf From aff78e51216e09a6e5c95c775d636530c85736fc Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 5 Jan 2010 15:05:53 -0800 Subject: Cache fixes: * We now cache negative lookups; clear them in Memcached_DataObject->insert() * Mark file.url as a unique key in statusnet.ini so its negative lookups are cleared properly (first save of a notice with a new URL was failing due to double-insert) * Now using serialization for default in-process cache instead of just saving objects; avoids potential corruption if you save an object to cache, change the original object, then fetch the same key from cache again --- classes/Memcached_DataObject.php | 1 + classes/statusnet.ini | 1 + lib/cache.php | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index aab1cace6..c31b2a546 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -142,6 +142,7 @@ class Memcached_DataObject extends DB_DataObject function insert() { + $this->decache(); // in case of cached negative lookups $result = parent::insert(); return $result; } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index ac31148da..0db2c5d6e 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -92,6 +92,7 @@ modified = 384 [file__keys] id = N +url = U [file_oembed] file_id = 129 diff --git a/lib/cache.php b/lib/cache.php index 85e8badc1..b7b34c050 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -120,7 +120,7 @@ class Cache if (Event::handle('StartCacheGet', array(&$key, &$value))) { if (array_key_exists($key, $this->_items)) { - $value = $this->_items[$key]; + $value = unserialize($this->_items[$key]); } Event::handle('EndCacheGet', array($key, &$value)); } @@ -146,7 +146,7 @@ class Cache if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { - $this->_items[$key] = $value; + $this->_items[$key] = serialize($value); $success = true; -- cgit v1.2.3-54-g00ecf From 92154969029e15673b84f5cc228099f2f5c1b942 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 5 Jan 2010 15:04:08 -0800 Subject: Ticket 2135: trim overlong repeats with ellipsis rather than failing. In web interface and retweet/repeat API we show the original untrimmed text, but some back-compat API messages will still show the trimmed 'RT' version. This matches Twitter's behavior on overlong retweets, though we're outputting the RT version in more API results than they do. --- classes/Notice.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index e8bc509a6..299ed696c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1356,12 +1356,21 @@ class Notice extends Memcached_DataObject { $author = Profile::staticGet('id', $this->profile_id); - // FIXME: truncate on long repeats...? - $content = sprintf(_('RT @%1$s %2$s'), $author->nickname, $this->content); + $maxlen = common_config('site', 'textlimit'); + if (mb_strlen($content) > $maxlen) { + // Web interface and current Twitter API clients will + // pull the original notice's text, but some older + // clients and RSS/Atom feeds will see this trimmed text. + // + // Unfortunately this is likely to lose tags or URLs + // at the end of long notices. + $content = mb_substr($content, 0, $maxlen - 4) . ' ...'; + } + return self::saveNew($repeater_id, $content, $source, array('repeat_of' => $this->id)); } -- cgit v1.2.3-54-g00ecf From 8af7ba022681b5a8b9141056055c5bd5c980e3e9 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 5 Jan 2010 16:15:12 -0800 Subject: Fix for overlong RT trimming: don't trim if textlimit is 0 (unlimited) --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index 299ed696c..9fa022650 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1361,7 +1361,7 @@ class Notice extends Memcached_DataObject $this->content); $maxlen = common_config('site', 'textlimit'); - if (mb_strlen($content) > $maxlen) { + if ($maxlen > 0 && mb_strlen($content) > $maxlen) { // Web interface and current Twitter API clients will // pull the original notice's text, but some older // clients and RSS/Atom feeds will see this trimmed text. -- cgit v1.2.3-54-g00ecf From 35d4587172955950957e017101c660976cfe68f9 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 5 Jan 2010 19:48:43 -1000 Subject: encache on insert instead of decaching --- classes/Memcached_DataObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index c31b2a546..d11bd6368 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -142,8 +142,8 @@ class Memcached_DataObject extends DB_DataObject function insert() { - $this->decache(); // in case of cached negative lookups $result = parent::insert(); + $this->encache(); // in case of cached negative lookups return $result; } -- cgit v1.2.3-54-g00ecf From b93244395f2c5643ae5e1be1e4e1d652c6d654c1 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 6 Jan 2010 11:10:33 -0800 Subject: Fix for broken profile flag admin UI: delete stray flag entries when users are deleted so broken entries don't litter the lookups. * added ProfileDeleteRelated event to match UserDeleteRelated, to allow plugins to add extra related tables on profile deletion * UserFlagPlugin: deleting flags when target profile is deleted * UserFlagPlugin: deleting flags when flagging user is deleted * UserFlagPlugin: fix for autoloader -- class names are case-insensitive. We may get lowercase class names coming in at times, such as when creating DB objects programatically from a table name. Note that any already-existing bogus entries need to be removed from the database: select * from user_flag_profile where (select id from profile where id=profile_id) is null; select * from user_flag_profile where (select id from user where id=user_id) is null; --- classes/Profile.php | 1 + plugins/UserFlag/UserFlagPlugin.php | 51 +++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 8 deletions(-) (limited to 'classes') diff --git a/classes/Profile.php b/classes/Profile.php index 03196447b..25d908dbf 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -504,6 +504,7 @@ class Profile extends Memcached_DataObject 'Reply', 'Group_member', ); + Event::handle('ProfileDeleteRelated', array($this, &$related)); foreach ($related as $cls) { $inst = new $cls(); diff --git a/plugins/UserFlag/UserFlagPlugin.php b/plugins/UserFlag/UserFlagPlugin.php index 602a5bfa8..a33869c19 100644 --- a/plugins/UserFlag/UserFlagPlugin.php +++ b/plugins/UserFlag/UserFlagPlugin.php @@ -102,20 +102,20 @@ class UserFlagPlugin extends Plugin function onAutoload($cls) { - switch ($cls) + switch (strtolower($cls)) { - case 'FlagprofileAction': - case 'AdminprofileflagAction': - case 'ClearflagAction': + case 'flagprofileaction': + case 'adminprofileflagaction': + case 'clearflagaction': include_once INSTALLDIR.'/plugins/UserFlag/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; - case 'FlagProfileForm': - case 'ClearFlagForm': + case 'flagprofileform': + case 'clearflagform': include_once INSTALLDIR.'/plugins/UserFlag/' . strtolower($cls . '.php'); return false; - case 'User_flag_profile': - include_once INSTALLDIR.'/plugins/UserFlag/'.$cls.'.php'; + case 'user_flag_profile': + include_once INSTALLDIR.'/plugins/UserFlag/'.ucfirst(strtolower($cls)).'.php'; return false; default: return true; @@ -258,4 +258,39 @@ class UserFlagPlugin extends Plugin } return true; } + + /** + * Ensure that flag entries for a profile are deleted + * along with the profile when deleting users. + * This prevents breakage of the admin profile flag UI. + * + * @param Profile $profile + * @param array &$related list of related tables; entries + * with matching profile_id will be deleted. + * + * @return boolean hook result + */ + + function onProfileDeleteRelated($profile, &$related) + { + $related[] = 'user_flag_profile'; + return true; + } + + /** + * Ensure that flag entries created by a user are deleted + * when that user gets deleted. + * + * @param User $user + * @param array &$related list of related tables; entries + * with matching user_id will be deleted. + * + * @return boolean hook result + */ + + function onUserDeleteRelated($user, &$related) + { + $related[] = 'user_flag_profile'; + return true; + } } -- cgit v1.2.3-54-g00ecf From 85554d0840642f4c1b47b50202dd648db565781c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 6 Jan 2010 13:23:39 -0800 Subject: Rearrange Memcached_DataObject::staticGet() to avoid "only variables can be passed by reference" warnings when DB lookup fails and we return false. (We need to keep it returning a reference because the extlib parent class is stuck in PHP 4-land and uses references everywhere, including this function's return value. Yuck!) Also changed pkeyGet to drop the reference, since it doesn't have an upstream equivalent. --- classes/Memcached_DataObject.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index d11bd6368..04f75b775 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -90,17 +90,16 @@ class Memcached_DataObject extends DB_DataObject unset($i); } $i = Memcached_DataObject::getcached($cls, $k, $v); - if ($i !== false) { // false == cache miss - return $i; - } else { + if ($i === false) { // false == cache miss $i = DB_DataObject::factory($cls); if (empty($i)) { - return false; + $i = false; + return $i; } $result = $i->get($k, $v); if ($result) { + // Hit! $i->encache(); - return $i; } else { // save the fact that no such row exists $c = self::memcache(); @@ -108,12 +107,16 @@ class Memcached_DataObject extends DB_DataObject $ck = self::cachekey($cls, $k, $v); $c->set($ck, null); } - return false; + $i = false; } } + return $i; } - function &pkeyGet($cls, $kv) + /** + * @fixme Should this return false on lookup fail to match staticGet? + */ + function pkeyGet($cls, $kv) { $i = Memcached_DataObject::multicache($cls, $kv); if ($i !== false) { // false == cache miss -- cgit v1.2.3-54-g00ecf From 4e2acd153b4e3208e24464478098fac458a13590 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 6 Jan 2010 14:28:40 -0800 Subject: ...and drop the unnecessary &reference from child class pkeyGet() overrides. --- classes/Avatar.php | 2 +- classes/Config.php | 2 +- classes/Fave.php | 2 +- classes/File_to_post.php | 2 +- classes/Group_block.php | 2 +- classes/Group_inbox.php | 2 +- classes/Group_member.php | 2 +- classes/Notice_inbox.php | 2 +- classes/Notice_tag.php | 2 +- classes/Profile_role.php | 2 +- classes/Queue_item.php | 2 +- classes/Subscription.php | 2 +- plugins/OpenID/User_openid_trustroot.php | 2 +- plugins/UserFlag/User_flag_profile.php | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'classes') diff --git a/classes/Avatar.php b/classes/Avatar.php index 8d6424e8b..91bde0f04 100644 --- a/classes/Avatar.php +++ b/classes/Avatar.php @@ -37,7 +37,7 @@ class Avatar extends Memcached_DataObject } } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Avatar', $kv); } diff --git a/classes/Config.php b/classes/Config.php index 6d914ca1f..43b99587f 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -120,7 +120,7 @@ class Config extends Memcached_DataObject return $result; } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Config', $kv); } diff --git a/classes/Fave.php b/classes/Fave.php index 11e876ff1..8113c8e16 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -32,7 +32,7 @@ class Fave extends Memcached_DataObject return $fave; } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Fave', $kv); } diff --git a/classes/File_to_post.php b/classes/File_to_post.php index e3db91b20..72a42b088 100644 --- a/classes/File_to_post.php +++ b/classes/File_to_post.php @@ -62,7 +62,7 @@ class File_to_post extends Memcached_DataObject } } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('File_to_post', $kv); } diff --git a/classes/Group_block.php b/classes/Group_block.php index de2cf5f6e..9f4d59295 100644 --- a/classes/Group_block.php +++ b/classes/Group_block.php @@ -40,7 +40,7 @@ class Group_block extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Group_block', $kv); } diff --git a/classes/Group_inbox.php b/classes/Group_inbox.php index 1af7439f7..2a0787e38 100644 --- a/classes/Group_inbox.php +++ b/classes/Group_inbox.php @@ -20,7 +20,7 @@ class Group_inbox extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Group_inbox', $kv); } diff --git a/classes/Group_member.php b/classes/Group_member.php index 3c23a991f..069b2c7a1 100644 --- a/classes/Group_member.php +++ b/classes/Group_member.php @@ -21,7 +21,7 @@ class Group_member extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Group_member', $kv); } diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index d3ddad656..e350e6e2f 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -101,7 +101,7 @@ class Notice_inbox extends Memcached_DataObject return $ids; } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Notice_inbox', $kv); } diff --git a/classes/Notice_tag.php b/classes/Notice_tag.php index 02740280f..79231f0b0 100644 --- a/classes/Notice_tag.php +++ b/classes/Notice_tag.php @@ -96,7 +96,7 @@ class Notice_tag extends Memcached_DataObject } } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Notice_tag', $kv); } diff --git a/classes/Profile_role.php b/classes/Profile_role.php index afa7fb74e..74aca3730 100644 --- a/classes/Profile_role.php +++ b/classes/Profile_role.php @@ -43,7 +43,7 @@ class Profile_role extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Profile_role', $kv); } diff --git a/classes/Queue_item.php b/classes/Queue_item.php index 295c321b5..9c673540d 100644 --- a/classes/Queue_item.php +++ b/classes/Queue_item.php @@ -55,7 +55,7 @@ class Queue_item extends Memcached_DataObject return null; } - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Queue_item', $kv); } diff --git a/classes/Subscription.php b/classes/Subscription.php index fedfd5f19..faf1331cd 100644 --- a/classes/Subscription.php +++ b/classes/Subscription.php @@ -46,7 +46,7 @@ class Subscription extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Subscription', $kv); } diff --git a/plugins/OpenID/User_openid_trustroot.php b/plugins/OpenID/User_openid_trustroot.php index 44288945b..0b411b8f7 100644 --- a/plugins/OpenID/User_openid_trustroot.php +++ b/plugins/OpenID/User_openid_trustroot.php @@ -22,7 +22,7 @@ class User_openid_trustroot extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('User_openid_trustroot', $kv); } diff --git a/plugins/UserFlag/User_flag_profile.php b/plugins/UserFlag/User_flag_profile.php index 658259452..063ed04ea 100644 --- a/plugins/UserFlag/User_flag_profile.php +++ b/plugins/UserFlag/User_flag_profile.php @@ -97,7 +97,7 @@ class User_flag_profile extends Memcached_DataObject * @return User_flag_profile found object or null */ - function &pkeyGet($kv) + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('User_flag_profile', $kv); } -- cgit v1.2.3-54-g00ecf From e50410683fa29dd424f893dd302d835828e0711f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 6 Jan 2010 16:34:18 -1000 Subject: only encache new objects when insert was successful --- classes/Memcached_DataObject.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index d11bd6368..15ca34821 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -143,7 +143,9 @@ class Memcached_DataObject extends DB_DataObject function insert() { $result = parent::insert(); - $this->encache(); // in case of cached negative lookups + if ($result) { + $this->encache(); // in case of cached negative lookups + } return $result; } -- cgit v1.2.3-54-g00ecf From b2bab7d7caddd7e57974e07c48663e1422853ebe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 6 Jan 2010 23:34:59 -0800 Subject: fixup keytypes so it returns the types no matter what kind of class it is --- classes/Memcached_DataObject.php | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'classes') diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 4e3cc5678..400b05f97 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -194,6 +194,17 @@ class Memcached_DataObject extends DB_DataObject function keyTypes() { + // ini-based classes return number-indexed arrays. handbuilt + // classes return column => keytype. Make this uniform. + + $keys = $this->keys(); + + $keyskeys = array_keys($keys); + + if (is_string($keyskeys[0])) { + return $keys; + } + global $_DB_DATAOBJECT; if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) { $this->databaseStructure(); -- cgit v1.2.3-54-g00ecf From deeaafe71239597878cb3fd78aa66314745796a3 Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Thu, 7 Jan 2010 20:59:31 +0000 Subject: Fixes to bugs where non-local messages were being wrong put in the public timeline and public xmpp feed --- actions/shownotice.php | 2 +- classes/Notice.php | 2 +- lib/jabber.php | 2 +- lib/noticelist.php | 2 +- lib/ping.php | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'classes') diff --git a/actions/shownotice.php b/actions/shownotice.php index 5d16fdad9..d09100f67 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -103,7 +103,7 @@ class ShownoticeAction extends OwnerDesignAction $this->user = User::staticGet('id', $this->profile->id); - if (! $this->notice->is_local) { + if ($this->notice->is_local == Notice::REMOTE_OMB) { common_redirect($this->notice->uri); return false; } diff --git a/classes/Notice.php b/classes/Notice.php index 9fa022650..9bda47827 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -63,7 +63,7 @@ class Notice extends Memcached_DataObject 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) - public $is_local; // tinyint(1) + public $is_local; // int(4) public $source; // varchar(32) public $conversation; // int(4) public $lat; // decimal(10,7) diff --git a/lib/jabber.php b/lib/jabber.php index 01aed8ffa..6e094c207 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -440,7 +440,7 @@ function jabber_public_notice($notice) // XXX: should we send out non-local messages if public,localonly // = false? I think not - if ($public && $notice->is_local) { + if ($public && $notice->is_local == LOCAL_PUBLIC) { $profile = Profile::staticGet($notice->profile_id); if (!$profile) { diff --git a/lib/noticelist.php b/lib/noticelist.php index 5eb2633ac..78abf34a7 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -379,7 +379,7 @@ class NoticeListItem extends Widget function showNoticeLink() { - if($this->notice->is_local){ + if($this->notice->is_local == Notice::LOCAL_PUBLIC || $this->notice->is_local == Notice::LOCAL_NONPUBLIC){ $noticeurl = common_local_url('shownotice', array('notice' => $this->notice->id)); }else{ diff --git a/lib/ping.php b/lib/ping.php index 5698c4038..735af9ef1 100644 --- a/lib/ping.php +++ b/lib/ping.php @@ -21,7 +21,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } function ping_broadcast_notice($notice) { - if (!$notice->is_local) { + if ($notice->is_local != Notice::LOCAL_PUBLIC && $notice->is_local != Notice::LOCAL_NONPUBLIC) { return true; } @@ -115,4 +115,4 @@ function ping_notice_tags($notice) { return implode('|', $tags); } return NULL; -} \ No newline at end of file +} -- cgit v1.2.3-54-g00ecf