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 --- lib/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') 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 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 'lib') 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 360fdb219dde7cb46b919aa18826df8ce5f4fdc6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Dec 2009 12:25:41 -0800 Subject: don't show notices with deleted profiles --- lib/noticelist.php | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/noticelist.php b/lib/noticelist.php index 4c11ceed6..5eb2633ac 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -191,6 +191,14 @@ class NoticeListItem extends Widget function show() { + if (empty($this->notice)) { + common_log(LOG_WARNING, "Trying to show missing notice; skipping."); + return; + } else if (empty($this->profile)) { + common_log(LOG_WARNING, "Trying to show missing profile (" . $this->notice->profile_id . "); skipping."); + return; + } + $this->showStart(); if (Event::handle('StartShowNoticeItem', array($this))) { $this->showNotice(); -- cgit v1.2.3-54-g00ecf From 98ce7daf5650ebd7e6f6bbaca6e57069ffccae55 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 29 Dec 2009 16:17:17 -0500 Subject: Implement user interface for user to preview what location they are sharing with a notice --- actions/geocode.php | 93 +++++++++++++++++++++++++++++++++++++++++++++++++ actions/newnotice.php | 2 +- js/jquery.cookie.js | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ js/util.js | 46 +++++++++++++++++++++--- lib/action.php | 1 + lib/noticeform.php | 6 ++++ lib/router.php | 3 +- 7 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 actions/geocode.php create mode 100644 js/jquery.cookie.js (limited to 'lib') diff --git a/actions/geocode.php b/actions/geocode.php new file mode 100644 index 000000000..7fd696baf --- /dev/null +++ b/actions/geocode.php @@ -0,0 +1,93 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2008, 2009, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Geocode action class + * + * @category Action + * @package StatusNet + * @author Craig Andrews + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ +class GeocodeAction extends Action +{ + function prepare($args) + { + parent::prepare($args); + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token. '. + 'Try again, please.')); + } + $this->lat = $this->trimmed('lat'); + $this->lon = $this->trimmed('lon'); + $this->location = Location::fromLatLon($this->lat, $this->lon); + return true; + } + + /** + * Class handler + * + * @param array $args query arguments + * + * @return nothing + * + **/ + function handle($args) + { + header('Content-Type: application/json; charset=utf-8'); + $location_object = array(); + $location_object['lat']=$this->lat; + $location_object['lon']=$this->lon; + if($this->location) { + $location_object['location_id']=$this->location->location_id; + $location_object['location_ns']=$this->location->location_ns; + $location_object['name']=$this->location->getName(); + $location_object['url']=$this->location->getUrl(); + } + print(json_encode($location_object)); + } + + /** + * Is this action read-only? + * + * @return boolean true + */ + + function isReadOnly($args) + { + return true; + } +} +?> diff --git a/actions/newnotice.php b/actions/newnotice.php index 2d9f0ff79..8d89e9da0 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -184,7 +184,7 @@ class NewnoticeAction extends Action $options = array('reply_to' => ($replyto == 'false') ? null : $replyto); - if ($user->shareLocation()) { + if ($user->shareLocation() && $this->arg('notice_data-location_enabled')) { $locOptions = Notice::locationOptions($this->trimmed('lat'), $this->trimmed('lon'), diff --git a/js/jquery.cookie.js b/js/jquery.cookie.js new file mode 100644 index 000000000..6df1faca2 --- /dev/null +++ b/js/jquery.cookie.js @@ -0,0 +1,96 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/js/util.js b/js/util.js index 0987c6cc0..f52c70ba4 100644 --- a/js/util.js +++ b/js/util.js @@ -50,7 +50,9 @@ var SN = { // StatusNet NoticeLat: 'notice_data-lat', NoticeLon: 'notice_data-lon', NoticeLocationId: 'notice_data-location_id', - NoticeLocationNs: 'notice_data-location_ns' + NoticeLocationNs: 'notice_data-location_ns', + NoticeLocationName: 'notice_data-location_name', + NoticeLocationCookieName: 'location_enabled' } }, @@ -436,10 +438,44 @@ var SN = { // StatusNet }, NoticeLocationAttach: function() { - if(navigator.geolocation) navigator.geolocation.watchPosition(function(position) { - $('#'+SN.C.S.NoticeLat).val(position.coords.latitude); - $('#'+SN.C.S.NoticeLon).val(position.coords.longitude); - }); + if($('#notice_data-location_enabled').size()) { + if(navigator.geolocation) { + $('#notice_data-location_enabled').change(function() { + $.cookie(SN.C.S.NoticeLocationCookieName, $('#notice_data-location_enabled').attr('checked')); + if($('#notice_data-location_enabled').attr('checked')) { + $('#'+SN.C.S.NoticeLocationName).show(); + $('#'+SN.C.S.NoticeLocationName).addClass('processing'); + navigator.geolocation.getCurrentPosition(function(position) { + $('#'+SN.C.S.NoticeLat).val(position.coords.latitude); + $('#'+SN.C.S.NoticeLon).val(position.coords.longitude); + var data = {'lat': position.coords.latitude,'lon': position.coords.longitude, 'token': $('#token').val()}; + $.getJSON($('#notice_data-location_enabled_container').attr('data-geocode-url'), data,function(location) { + $('#'+SN.C.S.NoticeLocationName).removeClass('processing'); + if(typeof(location.location_ns)!="undefined") $('#'+SN.C.S.NoticeLocationNs).val(location.location_ns); + if(typeof(location.location_id)!="undefined") $('#'+SN.C.S.NoticeLocationId).val(location.location_id); + if(typeof(location.name)=="undefined") { + $('#'+SN.C.S.NoticeLocationName).text(position.coords.latitude + ' ' + position.coords.longitude); + } else { + $('#'+SN.C.S.NoticeLocationName).text(location.name); + $('#'+SN.C.S.NoticeLocationName).attr('href',location.url); + } + }); + }); + } else { + $('#'+SN.C.S.NoticeLocationName).hide(); + $('#'+SN.C.S.NoticeLat).val(""); + $('#'+SN.C.S.NoticeLon).val(""); + $('#'+SN.C.S.NoticeLocationNs).val(""); + $('#'+SN.C.S.NoticeLocationId).val(""); + } + }); + var cookieVal = $.cookie(SN.C.S.NoticeLocationCookieName); + $('#notice_data-location_enabled').attr('checked',(cookieVal == null || cookieVal == 'true')); + $('#notice_data-location_enabled').change(); + } else { + $('#notice_data-location_enabled_container').remove(); + } + } }, NewDirectMessage: function() { diff --git a/lib/action.php b/lib/action.php index dac0e2583..35df03566 100644 --- a/lib/action.php +++ b/lib/action.php @@ -252,6 +252,7 @@ class Action extends HTMLOutputter // lawsuit if (Event::handle('StartShowJQueryScripts', array($this))) { $this->script('js/jquery.min.js'); $this->script('js/jquery.form.js'); + $this->script('js/jquery.cookie.js'); $this->script('js/jquery.joverlay.min.js'); Event::handle('EndShowJQueryScripts', array($this)); } diff --git a/lib/noticeform.php b/lib/noticeform.php index 593a1e932..d85de9c22 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -220,5 +220,11 @@ class NoticeForm extends Form 'name' => 'status_submit', 'type' => 'submit', 'value' => _('Send'))); + if($this->user->shareLocation()) { + $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); + $this->out->checkbox('notice_data-location_enabled',_('Share your location ')); + $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); + $this->out->elementEnd('div'); + } } } diff --git a/lib/router.php b/lib/router.php index 474e05996..7ec962460 100644 --- a/lib/router.php +++ b/lib/router.php @@ -100,7 +100,8 @@ class Router 'sandbox', 'unsandbox', 'silence', 'unsilence', 'repeat', - 'deleteuser'); + 'deleteuser', + 'geocode'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); -- cgit v1.2.3-54-g00ecf From 024704e0b70cb29107929cc2cce0ddc6b2d2e42b Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Wed, 30 Dec 2009 20:26:23 +0100 Subject: Remove trailing space in checkbox text. --- lib/noticeform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index d85de9c22..76715c35a 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -222,7 +222,7 @@ class NoticeForm extends Form 'value' => _('Send'))); if($this->user->shareLocation()) { $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); - $this->out->checkbox('notice_data-location_enabled',_('Share your location ')); + $this->out->checkbox('notice_data-location_enabled',_('Share your location')); $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); $this->out->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From 1e9c03e1993b5d2978ac4c5213a8a64e0150b4a2 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 30 Dec 2009 19:29:38 -0500 Subject: Enable memcache automatic compression, starting at 20k and only if compression gain is greater than 20%. Allows storage of larger objects (over 1mb in size uncompressed), such as huge LDAP schemas. Should also improve cache efficiency (allows more stuff to be stored in same memory) and reduce network latency (less data transfer) --- lib/util.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index ed81aeba1..df3110ddd 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1416,6 +1416,7 @@ function common_memcache() } else { $cache->addServer($servers); } + $cache->setCompressThreshold(20000, 0.2); } return $cache; } -- cgit v1.2.3-54-g00ecf From 4985582880b56f23226dfffb3f81140d8d4c055f Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 12:43:33 +0000 Subject: Fixed Event end name --- lib/noticeform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index 76715c35a..0af497099 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -203,7 +203,7 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_id', empty($this->location_id) ? null : $this->location_id, 'location_id'); $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? null : $this->location_ns, 'location_ns'); - Event::handle('StartShowNoticeFormData', array($this)); + Event::handle('EndShowNoticeFormData', array($this)); } } -- cgit v1.2.3-54-g00ecf From 58714808443204ecbd98b9763aeaeb1929341213 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 12:52:39 +0000 Subject: Moved shareLocation data from formActions() to formData() --- lib/noticeform.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index 0af497099..bfdab7738 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -203,6 +203,13 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_id', empty($this->location_id) ? null : $this->location_id, 'location_id'); $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? null : $this->location_ns, 'location_ns'); + if($this->user->shareLocation()) { + $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); + $this->out->checkbox('notice_data-location_enabled',_('Share your location')); + $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); + $this->out->elementEnd('div'); + } + Event::handle('EndShowNoticeFormData', array($this)); } } @@ -220,11 +227,5 @@ class NoticeForm extends Form 'name' => 'status_submit', 'type' => 'submit', 'value' => _('Send'))); - if($this->user->shareLocation()) { - $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); - $this->out->checkbox('notice_data-location_enabled',_('Share your location')); - $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); - $this->out->elementEnd('div'); - } } } -- cgit v1.2.3-54-g00ecf From 923e27b01a81c70ab52bc1b5856368143d0d32cf Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 14:23:11 +0000 Subject: Fix to grab and use the actual lat/lon values from the user profile --- lib/noticeform.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index bfdab7738..c60ac29c3 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -110,6 +110,8 @@ class NoticeForm extends Form $this->user = common_current_user(); } + $this->profile = $this->user->getProfile(); + if (common_config('attachments', 'uploads')) { $this->enctype = 'multipart/form-data'; } @@ -198,10 +200,11 @@ class NoticeForm extends Form $this->out->hidden('notice_return-to', $this->action, 'returnto'); } $this->out->hidden('notice_in-reply-to', $this->inreplyto, 'inreplyto'); - $this->out->hidden('notice_data-lat', empty($this->lat) ? null : $this->lat, 'lat'); - $this->out->hidden('notice_data-lon', empty($this->lon) ? null : $this->lon, 'lon'); - $this->out->hidden('notice_data-location_id', empty($this->location_id) ? null : $this->location_id, 'location_id'); - $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? null : $this->location_ns, 'location_ns'); + + $this->out->hidden('notice_data-lat', empty($this->profile->lat) ? null : $this->profile->lat, 'lat'); + $this->out->hidden('notice_data-lon', empty($this->profile->lon) ? null : $this->profile->lon, 'lon'); + $this->out->hidden('notice_data-location_id', empty($this->profile->location_id) ? null : $this->profile->location_id, 'location_id'); + $this->out->hidden('notice_data-location_ns', empty($this->profile->location_ns) ? null : $this->profile->location_ns, 'location_ns'); if($this->user->shareLocation()) { $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); -- cgit v1.2.3-54-g00ecf From 4efa841ba330cedd4ad71349a8196f18d5546cb8 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 14:24:27 +0000 Subject: If user doesn't want to share their location (which is globally set from their profile settings), don't bother to output form data for lat/long in the notice form. --- lib/noticeform.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index c60ac29c3..50b2e6893 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -201,12 +201,12 @@ class NoticeForm extends Form } $this->out->hidden('notice_in-reply-to', $this->inreplyto, 'inreplyto'); - $this->out->hidden('notice_data-lat', empty($this->profile->lat) ? null : $this->profile->lat, 'lat'); - $this->out->hidden('notice_data-lon', empty($this->profile->lon) ? null : $this->profile->lon, 'lon'); - $this->out->hidden('notice_data-location_id', empty($this->profile->location_id) ? null : $this->profile->location_id, 'location_id'); - $this->out->hidden('notice_data-location_ns', empty($this->profile->location_ns) ? null : $this->profile->location_ns, 'location_ns'); + if ($this->user->shareLocation()) { + $this->out->hidden('notice_data-lat', empty($this->profile->lat) ? null : $this->profile->lat, 'lat'); + $this->out->hidden('notice_data-lon', empty($this->profile->lon) ? null : $this->profile->lon, 'lon'); + $this->out->hidden('notice_data-location_id', empty($this->profile->location_id) ? null : $this->profile->location_id, 'location_id'); + $this->out->hidden('notice_data-location_ns', empty($this->profile->location_ns) ? null : $this->profile->location_ns, 'location_ns'); - if($this->user->shareLocation()) { $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); $this->out->checkbox('notice_data-location_enabled',_('Share your location')); $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); -- cgit v1.2.3-54-g00ecf From c986f59143b1969dc4ae324409295728b1d06e82 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 14:34:07 +0000 Subject: If user is sharing their location (based on profile setting), then enable it for form notice by default. This can be overriden by the cookie to preserve states. --- lib/noticeform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index 50b2e6893..f45e6629b 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -208,7 +208,7 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_ns', empty($this->profile->location_ns) ? null : $this->profile->location_ns, 'location_ns'); $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); - $this->out->checkbox('notice_data-location_enabled',_('Share your location')); + $this->out->checkbox('notice_data-location_enabled', _('Share your location'), true); $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); $this->out->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From 0320bf2fb3cdd4b9e6b635485421833fde447da8 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 15:46:43 +0000 Subject: Use the location setting profile as secondary --- lib/noticeform.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index f45e6629b..5afa41e25 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -202,10 +202,10 @@ class NoticeForm extends Form $this->out->hidden('notice_in-reply-to', $this->inreplyto, 'inreplyto'); if ($this->user->shareLocation()) { - $this->out->hidden('notice_data-lat', empty($this->profile->lat) ? null : $this->profile->lat, 'lat'); - $this->out->hidden('notice_data-lon', empty($this->profile->lon) ? null : $this->profile->lon, 'lon'); - $this->out->hidden('notice_data-location_id', empty($this->profile->location_id) ? null : $this->profile->location_id, 'location_id'); - $this->out->hidden('notice_data-location_ns', empty($this->profile->location_ns) ? null : $this->profile->location_ns, 'location_ns'); + $this->out->hidden('notice_data-lat', empty($this->lat) ? (empty($this->profile->lat) ? null : $this->profile->lat) : $this->lat, 'lat'); + $this->out->hidden('notice_data-lon', empty($this->lon) ? (empty($this->profile->lon) ? null : $this->profile->lon) : $this->lon, 'lon'); + $this->out->hidden('notice_data-location_id', empty($this->location_id) ? (empty($this->profile->location_id) ? null : $this->profile->location_id) : $this->location_id, 'location_id'); + $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns'); $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); $this->out->checkbox('notice_data-location_enabled', _('Share your location'), true); -- cgit v1.2.3-54-g00ecf From 8872d91483b689d168244ff0df2fa4b5b23a38cc Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 16:44:24 +0000 Subject: Removed style information out of HTML --- lib/noticeform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticeform.php b/lib/noticeform.php index 5afa41e25..98f15ca09 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -209,7 +209,7 @@ class NoticeForm extends Form $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); $this->out->checkbox('notice_data-location_enabled', _('Share your location'), true); - $this->out->element('a', array('style' => 'display: none', 'target' => '_blank', 'id' => 'notice_data-location_name'), _('Finding your location...')); + $this->out->element('a', array('id' => 'notice_data-location_name'), _('Finding your location...')); $this->out->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From dde6415a6a91eb6670a80279a344ab6cc56ef17d Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 18:08:21 +0000 Subject: Moved JavaScript dependant stuff out of noticeform. --- js/util.js | 29 ++++++++++++++++++++++------- lib/noticeform.php | 4 ++-- 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/js/util.js b/js/util.js index 8ac0cbd66..41b3fdb25 100644 --- a/js/util.js +++ b/js/util.js @@ -440,8 +440,20 @@ var SN = { // StatusNet NoticeLocationAttach: function() { if ($('#notice_data-location_enabled').length > 0) { if (navigator.geolocation) { - $('#notice_data-location_enabled').change(function() { + var NLE = $('#notice_data-location_wrap'); + var geocodeURL = NLE.attr('title'); + + NLE.change(function() { + NLE.removeAttr('title'); + $.cookie(SN.C.S.NoticeLocationCookieName, $('#notice_data-location_enabled').attr('checked')); + + var NLN = $('#'+SN.C.S.NoticeLocationName); + if (NLN.length > 0) { + NLN.remove(); + } + + NLE.append('Geo'); NLN = $('#'+SN.C.S.NoticeLocationName); if ($('#notice_data-location_enabled').attr('checked') === true) { @@ -458,8 +470,9 @@ var SN = { // StatusNet 'token': $('#token').val() }; - $.getJSON($('#notice_data-location_enabled_container').attr('data-geocode-url'), data, function(location) { - NLN.removeClass('processing'); + $.getJSON(geocodeURL, data, function(location) { + NLN.replaceWith(''); + NLN = $('#'+SN.C.S.NoticeLocationName); if (typeof(location.location_ns) != 'undefined') { $('#'+SN.C.S.NoticeLocationNs).val(location.location_ns); @@ -470,12 +483,14 @@ var SN = { // StatusNet } if (typeof(location.name) == 'undefined') { - NLN.text(position.coords.latitude + ';' + position.coords.longitude); + NLN_text = position.coords.latitude + ';' + position.coords.longitude; } else { - NLN.text(location.name); - NLN.attr('href',location.url); + NLN_text = location.name; } + + NLN.attr('href', location.url); + NLN.text(NLN_text); }); }); } @@ -490,7 +505,7 @@ var SN = { // StatusNet var cookieVal = $.cookie(SN.C.S.NoticeLocationCookieName); $('#notice_data-location_enabled').attr('checked',(cookieVal == null || cookieVal == 'true')); - $('#notice_data-location_enabled').change(); + NLE.change(); } } }, diff --git a/lib/noticeform.php b/lib/noticeform.php index 98f15ca09..7ed880442 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -207,9 +207,9 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_id', empty($this->location_id) ? (empty($this->profile->location_id) ? null : $this->profile->location_id) : $this->location_id, 'location_id'); $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns'); - $this->out->elementStart('div',array('id' => 'notice_data-location_enabled_container', 'data-geocode-url' => common_local_url('geocode'))); + $this->out->elementStart('div', array('id' => 'notice_data-location_wrap', + 'title' => common_local_url('geocode'))); $this->out->checkbox('notice_data-location_enabled', _('Share your location'), true); - $this->out->element('a', array('id' => 'notice_data-location_name'), _('Finding your location...')); $this->out->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From 01dbee2ba5280d97ddd0bb82217e8b3e7680e67b Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 31 Dec 2009 18:41:10 +0000 Subject: Initial UI for geo location share option in notice form --- js/util.js | 2 +- lib/noticeform.php | 1 + theme/base/css/display.css | 15 +++++++++++++++ theme/identica/css/display.css | 4 ++++ 4 files changed, 21 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/js/util.js b/js/util.js index 0969ba5e2..dd7a74a7a 100644 --- a/js/util.js +++ b/js/util.js @@ -455,7 +455,7 @@ var SN = { // StatusNet NLN.remove(); } - NLE.append('Geo'); + NLE.prepend('Geo'); NLN = $('#'+SN.C.S.NoticeLocationName); if ($('#notice_data-location_enabled').attr('checked') === true) { diff --git a/lib/noticeform.php b/lib/noticeform.php index 7ed880442..d35655a0b 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -208,6 +208,7 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns'); $this->out->elementStart('div', array('id' => 'notice_data-location_wrap', + 'class' => 'success', 'title' => common_local_url('geocode'))); $this->out->checkbox('notice_data-location_enabled', _('Share your location'), true); $this->out->elementEnd('div'); diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 29c7ee963..d6a50ac60 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -566,6 +566,21 @@ overflow:auto; float:right; font-size:0.8em; } +.form_notice #notice_data-location_wrap input { +margin-right:7px; +float:left; +} +.form_notice #notice_data-location_wrap label { +font-weight:normal; +font-size:1em; +} +.form_notice #notice_data-location_name { +display:block; +line-height:1.6; +} +.form_notice span#notice_data-location_name { +padding-left:18px; +} button.close { width:16px; diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index e86ee2437..78a0707ce 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -111,6 +111,10 @@ box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1); text-shadow:none; } +.form_notice #notice_data-location_name { +background-position:0 47%; +} + a, .form_settings input.form_action-primary, .notice-options input, -- cgit v1.2.3-54-g00ecf From ec5850d26a46b88c14579959c8bcf34e936b087e Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sun, 3 Jan 2010 00:33:41 +0000 Subject: Changed location share representation to be more like the file attachment. Init UI. Probably a little buggy. --- js/util.js | 38 ++++++++++++++++++++++++++--------- lib/noticeform.php | 3 +-- theme/base/css/display.css | 29 ++++++++++++++++++-------- theme/base/images/icons/icons-01.gif | Bin 3443 -> 3533 bytes theme/identica/css/display.css | 9 ++++++++- 5 files changed, 59 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/js/util.js b/js/util.js index dd7a74a7a..8ee0dd05d 100644 --- a/js/util.js +++ b/js/util.js @@ -52,7 +52,9 @@ var SN = { // StatusNet NoticeLocationId: 'notice_data-location_id', NoticeLocationNs: 'notice_data-location_ns', NoticeLocationName: 'notice_data-location_name', - NoticeLocationCookieName: 'location_enabled' + NoticeLocationCookieName: 'location_enabled', + NoticeDataGeo: 'notice_data-geo', + NoticeDataGeoSelected: 'notice_data-geo_selected' } }, @@ -438,29 +440,46 @@ var SN = { // StatusNet }, NoticeLocationAttach: function() { - if ($('#notice_data-location_enabled').length > 0) { + var NDG = $('#'+SN.C.S.NoticeDataGeo); + if (NDG.length > 0) { + NDG.attr('title', NDG.text()); var NLE = $('#notice_data-location_wrap'); var geocodeURL = NLE.attr('title'); - NLE.insertAfter('#'+SN.C.S.FormNotice+' fieldset'); + var S = '
'; + var NDGS = $('#'+SN.C.S.NoticeDataGeoSelected); + + if (NDGS.length > 0) { + NDGS.replaceWith(S); + } + else { + $('#'+SN.C.S.FormNotice).append(S); + } + NDGS = $('#'+SN.C.S.NoticeDataGeoSelected); + + $('#'+SN.C.S.NoticeDataGeoSelected+' button.close').click(function(){ + $('#'+SN.C.S.NoticeDataGeoSelected).remove(); + $('#'+SN.C.S.NoticeDataGeo).attr('checked', false); + }); if (navigator.geolocation) { NLE.change(function() { NLE.removeAttr('title'); - $.cookie(SN.C.S.NoticeLocationCookieName, $('#notice_data-location_enabled').attr('checked')); + $.cookie(SN.C.S.NoticeLocationCookieName, $('#'+SN.C.S.NoticeDataGeo).attr('checked')); var NLN = $('#'+SN.C.S.NoticeLocationName); if (NLN.length > 0) { NLN.remove(); } - NLE.prepend('Geo'); + NDGS.prepend('Geo'); NLN = $('#'+SN.C.S.NoticeLocationName); - if ($('#notice_data-location_enabled').attr('checked') === true) { - NLN.show(); + if ($('#'+SN.C.S.NoticeDataGeo).attr('checked') === true) { + NDGS.show(); NLN.addClass('processing'); + $('label[for=notice_data-geo]').addClass('checked'); navigator.geolocation.getCurrentPosition(function(position) { $('#'+SN.C.S.NoticeLat).val(position.coords.latitude); @@ -497,7 +516,8 @@ var SN = { // StatusNet }); } else { - NLN.hide(); + $('label[for=notice_data-geo]').removeClass('checked'); + NDGS.hide(); $('#'+SN.C.S.NoticeLat).val(''); $('#'+SN.C.S.NoticeLon).val(''); $('#'+SN.C.S.NoticeLocationNs).val(''); @@ -506,7 +526,7 @@ var SN = { // StatusNet }); var cookieVal = $.cookie(SN.C.S.NoticeLocationCookieName); - $('#notice_data-location_enabled').attr('checked', (cookieVal == null || cookieVal == 'true')); + $('#'+SN.C.S.NoticeDataGeo).attr('checked', (cookieVal == null || cookieVal == 'true')); NLE.change(); } } diff --git a/lib/noticeform.php b/lib/noticeform.php index d35655a0b..99865645a 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -208,9 +208,8 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns'); $this->out->elementStart('div', array('id' => 'notice_data-location_wrap', - 'class' => 'success', 'title' => common_local_url('geocode'))); - $this->out->checkbox('notice_data-location_enabled', _('Share your location'), true); + $this->out->checkbox('notice_data-geo', _('Share your location'), true); $this->out->elementEnd('div'); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index a0b12a9f4..fc8762cdc 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -554,31 +554,44 @@ width:81.5%; margin-bottom:0; line-height:1.618; } -.form_notice #notice_data-attach_selected code { +.form_notice #notice_data-attach_selected code, +.form_notice #notice_data-location_name { float:left; -width:90%; +width:87%; display:block; -font-size:1.1em; line-height:1.8; overflow:auto; } -.form_notice #notice_data-attach_selected button { +.form_notice #notice_data-attach_selected code { +font-size:1.1em; +} +.form_notice #notice_data-attach_selected button.close, +.form_notice #notice_data-geo_selected button.close { float:right; font-size:0.8em; } + +.form_notice #notice_data-location_wrap label { +position:absolute; +top:25px; +right:4px; +left:auto; +cursor:pointer; +width:16px; +height:16px; +display:block; +} .form_notice #notice_data-location_wrap input { -margin-right:7px; -float:left; -top:3px; +display:none; } .form_notice #notice_data-location_wrap label { font-weight:normal; font-size:1em; margin-bottom:0; +text-indent:-9999px; } .form_notice #notice_data-location_name { display:block; -line-height:1.6; padding-left:21px; } diff --git a/theme/base/images/icons/icons-01.gif b/theme/base/images/icons/icons-01.gif index cda932161..03db8c09c 100644 Binary files a/theme/base/images/icons/icons-01.gif and b/theme/base/images/icons/icons-01.gif differ diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 34be6eefa..a47837387 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -117,6 +117,12 @@ background-position:0 47%; .form_notice a#notice_data-location_name { background-position:0 -1711px; } +.form_notice label[for=notice_data-geo] { +background-position:0 -1780px; +} +.form_notice label[for=notice_data-geo].checked { +background-position:0 -1847px; +} a, .form_settings input.form_action-primary, @@ -185,7 +191,8 @@ button.close, .entity_silence input.submit, .entity_delete input.submit, .notice-options .repeated, -.form_notice a#notice_data-location_name { +.form_notice a#notice_data-location_name, +.form_notice label[for=notice_data-geo] { background-image:url(../../base/images/icons/icons-01.gif); background-repeat:no-repeat; background-color:transparent; -- cgit v1.2.3-54-g00ecf From 3b912ac97e2c19c2861065dbf2584a42810aa533 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 16:27:04 -1000 Subject: fixup memcache functions --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index df3110ddd..22dc0f934 100644 --- a/lib/util.php +++ b/lib/util.php @@ -62,7 +62,7 @@ function common_init_language() // gettext will still select the right language. $language = common_language(); $locale_set = common_init_locale($language); - + setlocale(LC_CTYPE, 'C'); // So we do not have to make people install the gettext locales $path = common_config('site','locale_path'); -- cgit v1.2.3-54-g00ecf From c5d23e27a6a34e02090ebcece60dfa5b7f814488 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 20:26:33 -1000 Subject: Make caching a plugin system --- lib/cache.php | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.php | 31 ++-------------- 2 files changed, 116 insertions(+), 28 deletions(-) create mode 100644 lib/cache.php (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php new file mode 100644 index 000000000..d1ba65dab --- /dev/null +++ b/lib/cache.php @@ -0,0 +1,113 @@ +. + * + * @category Cache + * @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/ + */ + +/** + * Interface for caching + * + * An abstract interface for caching. + * + */ + +class Cache +{ + var $_items = array(); + static $_inst = null; + + static function instance() + { + if (is_null(self::$_inst)) { + self::$_inst = new Cache(); + } + + return self::$_inst; + } + + static function key($extra) + { + $base_key = common_config('memcached', 'base'); + + if (empty($base_key)) { + $base_key = common_keyize(common_config('site', 'name')); + } + + return 'statusnet:' . $base_key . ':' . $extra; + } + + static function keyize($str) + { + $str = strtolower($str); + $str = preg_replace('/\s/', '_', $str); + return $str; + } + + function get($key) + { + $value = null; + + if (!Event::handle('StartCacheGet', array(&$key, &$value))) { + if (array_key_exists($_items, $key)) { + common_log(LOG_INFO, 'Cache HIT for key ' . $key); + $value = $_items[$key]; + } else { + common_log(LOG_INFO, 'Cache MISS for key ' . $key); + } + Event::handle('EndCacheGet', array($key, &$value)); + } + + return $value; + } + + function set($key, $value, $flag=null, $expiry=null) + { + $success = false; + + if (!Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { + common_log(LOG_INFO, 'Setting cache value for key ' . $key); + $_items[$key] = $value; + $success = true; + Event::handle('EndCacheSet', array($key, $value, $flag, $expiry)); + } + + return $success; + } + + function delete($key) + { + $success = false; + + if (!Event::handle('StartCacheDelete', array(&$key, &$success))) { + common_log(LOG_INFO, 'Deleting cache value for key ' . $key); + unset($_items[$key]); + $success = true; + Event::handle('EndCacheDelete', array($key)); + } + + return $success; + } +} diff --git a/lib/util.php b/lib/util.php index 22dc0f934..63656b604 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1384,42 +1384,17 @@ function common_session_token() function common_cache_key($extra) { - $base_key = common_config('memcached', 'base'); - - if (empty($base_key)) { - $base_key = common_keyize(common_config('site', 'name')); - } - - return 'statusnet:' . $base_key . ':' . $extra; + return Cache::key($extra); } function common_keyize($str) { - $str = strtolower($str); - $str = preg_replace('/\s/', '_', $str); - return $str; + return Cache::keyize($str); } function common_memcache() { - static $cache = null; - if (!common_config('memcached', 'enabled')) { - return null; - } else { - if (!$cache) { - $cache = new Memcache(); - $servers = common_config('memcached', 'server'); - if (is_array($servers)) { - foreach($servers as $server) { - $cache->addServer($server); - } - } else { - $cache->addServer($servers); - } - $cache->setCompressThreshold(20000, 0.2); - } - return $cache; - } + return Cache::instance(); } function common_license_terms($uri) -- cgit v1.2.3-54-g00ecf From e1de1bf0fef4c7ae21ebca99dc4f38746c9d2df2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 20:32:56 -1000 Subject: fix default array implementation checks --- lib/cache.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index d1ba65dab..31d2f84d2 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -71,9 +71,9 @@ class Cache $value = null; if (!Event::handle('StartCacheGet', array(&$key, &$value))) { - if (array_key_exists($_items, $key)) { + if (array_key_exists($key, $this->_items)) { common_log(LOG_INFO, 'Cache HIT for key ' . $key); - $value = $_items[$key]; + $value = $this->_items[$key]; } else { common_log(LOG_INFO, 'Cache MISS for key ' . $key); } @@ -89,7 +89,7 @@ class Cache if (!Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { common_log(LOG_INFO, 'Setting cache value for key ' . $key); - $_items[$key] = $value; + $this->_items[$key] = $value; $success = true; Event::handle('EndCacheSet', array($key, $value, $flag, $expiry)); } @@ -102,8 +102,10 @@ class Cache $success = false; if (!Event::handle('StartCacheDelete', array(&$key, &$success))) { - common_log(LOG_INFO, 'Deleting cache value for key ' . $key); - unset($_items[$key]); + if (array_key_exists($key, $this->_items[$key])) { + common_log(LOG_INFO, 'Deleting cache value for key ' . $key); + unset($this->_items[$key]); + } $success = true; Event::handle('EndCacheDelete', array($key)); } -- cgit v1.2.3-54-g00ecf From 65d07b657dfbda0f696109769192d54856b5b8e8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 20:37:30 -1000 Subject: invert if for cache handling --- lib/cache.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index 31d2f84d2..9ea531c07 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -70,7 +70,7 @@ class Cache { $value = null; - if (!Event::handle('StartCacheGet', array(&$key, &$value))) { + if (Event::handle('StartCacheGet', array(&$key, &$value))) { if (array_key_exists($key, $this->_items)) { common_log(LOG_INFO, 'Cache HIT for key ' . $key); $value = $this->_items[$key]; @@ -87,7 +87,7 @@ class Cache { $success = false; - if (!Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { + if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { common_log(LOG_INFO, 'Setting cache value for key ' . $key); $this->_items[$key] = $value; $success = true; @@ -101,7 +101,7 @@ class Cache { $success = false; - if (!Event::handle('StartCacheDelete', array(&$key, &$success))) { + if (Event::handle('StartCacheDelete', array(&$key, &$success))) { if (array_key_exists($key, $this->_items[$key])) { common_log(LOG_INFO, 'Deleting cache value for key ' . $key); unset($this->_items[$key]); -- cgit v1.2.3-54-g00ecf From 1e1062ca9ca51ef618600459240bb0d497a47491 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 21:00:42 -1000 Subject: Make cache.php PHPCS-clean --- lib/cache.php | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index 9ea531c07..63f582861 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -30,15 +30,31 @@ /** * Interface for caching * - * An abstract interface for caching. + * An abstract interface for caching. Because we originally used the + * Memcache plugin directly, the interface uses a small subset of the + * Memcache interface. * + * @category Cache + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ */ class Cache { - var $_items = array(); + var $_items = array(); static $_inst = null; + /** + * Singleton constructor + * + * Use this to get the singleton instance of Cache. + * + * @return Cache cache object + */ + static function instance() { if (is_null(self::$_inst)) { @@ -48,6 +64,18 @@ class Cache return self::$_inst; } + /** + * Create a cache key from input text + * + * Builds a cache key from input text. Helps to namespace + * the cache area (if shared with other applications or sites) + * and prevent conflicts. + * + * @param string $extra the real part of the key + * + * @return string full key + */ + static function key($extra) { $base_key = common_config('memcached', 'base'); @@ -59,6 +87,16 @@ class Cache return 'statusnet:' . $base_key . ':' . $extra; } + /** + * Make a string suitable for use as a key + * + * Useful for turning primary keys of tables into cache keys. + * + * @param string $str string to turn into a key + * + * @return string keyized string + */ + static function keyize($str) { $str = strtolower($str); @@ -66,6 +104,16 @@ class Cache return $str; } + /** + * Get a value associated with a key + * + * The value should have been set previously. + * + * @param string $key Lookup key + * + * @return string retrieved value or null if unfound + */ + function get($key) { $value = null; @@ -83,20 +131,44 @@ class Cache return $value; } + /** + * Set the value associated with a key + * + * @param string $key The key to use for lookups + * @param string $value The value to store + * @param integer $flag Flags to use, mostly ignored + * @param integer $expiry Expiry value, mostly ignored + * + * @return boolean success flag + */ + function set($key, $value, $flag=null, $expiry=null) { $success = false; - if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { + if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag, + &$expiry, &$success))) { common_log(LOG_INFO, 'Setting cache value for key ' . $key); + $this->_items[$key] = $value; + $success = true; - Event::handle('EndCacheSet', array($key, $value, $flag, $expiry)); + + Event::handle('EndCacheSet', array($key, $value, $flag, + $expiry)); } return $success; } + /** + * Delete the value associated with a key + * + * @param string $key Key to delete + * + * @return boolean success flag + */ + function delete($key) { $success = false; -- cgit v1.2.3-54-g00ecf From cc5534d180625b3d34f7039c0b95b034f3674a20 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 2 Jan 2010 21:16:59 -1000 Subject: First version of Memcache plugin --- lib/cache.php | 2 +- lib/common.php | 12 ++++ lib/default.php | 7 +- plugins/MemcachePlugin.php | 162 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 plugins/MemcachePlugin.php (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index 63f582861..23657bbf3 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -78,7 +78,7 @@ class Cache static function key($extra) { - $base_key = common_config('memcached', 'base'); + $base_key = common_config('cache', 'base'); if (empty($base_key)) { $base_key = common_keyize(common_config('site', 'name')); diff --git a/lib/common.php b/lib/common.php index 7fa1910af..b0e5c4390 100644 --- a/lib/common.php +++ b/lib/common.php @@ -210,6 +210,18 @@ if ($_db_name != 'statusnet' && !array_key_exists('ini_'.$_db_name, $config['db' $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/statusnet.ini'; } +// Backwards compatibility + +if (array_key_exists('memcached', $config)) { + if ($config['memcached']['enabled']) { + addPlugin('Memcache', array('servers' => $config['memcached']['server'])); + } + + if (!empty($config['memcached']['base'])) { + $config['cache']['base'] = $config['memcached']['base']; + } +} + function __autoload($cls) { if (file_exists(INSTALLDIR.'/classes/' . $cls . '.php')) { diff --git a/lib/default.php b/lib/default.php index 8a70ed3fa..eea11eb2b 100644 --- a/lib/default.php +++ b/lib/default.php @@ -147,11 +147,8 @@ $default = array('enabled' => true, 'consumer_key' => null, 'consumer_secret' => null), - 'memcached' => - array('enabled' => false, - 'server' => 'localhost', - 'base' => null, - 'port' => 11211), + 'cache' => + array('base' => null), 'ping' => array('notify' => array()), 'inboxes' => diff --git a/plugins/MemcachePlugin.php b/plugins/MemcachePlugin.php new file mode 100644 index 000000000..acbec135e --- /dev/null +++ b/plugins/MemcachePlugin.php @@ -0,0 +1,162 @@ +. + * + * @category Cache + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * A plugin to use memcache for the cache interface + * + * This used to be encoded as config-variable options in the core code; + * it's now broken out to a separate plugin. The same interface can be + * implemented by other plugins. + * + * @category Cache + * @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/ + */ + +class MemcachePlugin extends Plugin +{ + private $_conn = null; + public $servers = array('127.0.0.1;11211'); + + /** + * Initialize the plugin + * + * Note that onStartCacheGet() may have been called before this! + * + * @return boolean flag value + */ + + function onInitializePlugin() + { + $this->_ensureConn(); + return true; + } + + /** + * Get a value associated with a key + * + * The value should have been set previously. + * + * @param string &$key in; Lookup key + * @param mixed &$value out; value associated with key + * + * @return boolean hook success + */ + + function onStartCacheGet(&$key, &$value) + { + $this->_ensureConn(); + $value = $this->_conn->get($key); + Event::handle('EndCacheGet', array($key, &$value)); + return false; + } + + /** + * Associate a value with a key + * + * @param string &$key in; Key to use for lookups + * @param mixed &$value in; Value to associate + * @param integer &$flag in; Flag (passed through to Memcache) + * @param integer &$expiry in; Expiry (passed through to Memcache) + * @param boolean &$success out; Whether the set was successful + * + * @return boolean hook success + */ + + function onStartCacheSet(&$key, &$value, &$flag, &$expiry, &$success) + { + $this->_ensureConn(); + $success = $this->_conn->set($key, $value, $flag, $expiry); + Event::handle('EndCacheSet', array($key, $value, $flag, + $expiry)); + return false; + } + + /** + * Delete a value associated with a key + * + * @param string &$key in; Key to lookup + * @param boolean &$success out; whether it worked + * + * @return boolean hook success + */ + + function onStartCacheDelete(&$key, &$success) + { + $this->_ensureConn(); + $success = $this->_conn->delete($key); + Event::handle('EndCacheDelete', array($key)); + return false; + } + + /** + * Ensure that a connection exists + * + * Checks the instance $_conn variable and connects + * if it is empty. + * + * @return void + */ + + private function _ensureConn() + { + if (empty($this->_conn)) { + $this->_conn = new Memcache(); + + if (is_array($this->servers)) { + foreach ($this->servers as $server) { + list($host, $port) = explode(';', $server); + if (empty($port)) { + $port = 11211; + } + + $this->_conn->addServer($host, $port); + } + } else { + $this->_conn->addServer($this->servers); + list($host, $port) = explode(';', $this->servers); + if (empty($port)) { + $port = 11211; + } + $this->_conn->addServer($host, $port); + } + } + } +} + -- cgit v1.2.3-54-g00ecf From bfa3aa0e7f39ba9b8ff920c480efb4cf52007532 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 3 Jan 2010 11:28:15 -1000 Subject: Remove logging from default cache --- lib/cache.php | 5 ----- 1 file changed, 5 deletions(-) (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index 23657bbf3..253839fb1 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -120,10 +120,7 @@ class Cache if (Event::handle('StartCacheGet', array(&$key, &$value))) { if (array_key_exists($key, $this->_items)) { - common_log(LOG_INFO, 'Cache HIT for key ' . $key); $value = $this->_items[$key]; - } else { - common_log(LOG_INFO, 'Cache MISS for key ' . $key); } Event::handle('EndCacheGet', array($key, &$value)); } @@ -148,7 +145,6 @@ class Cache if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { - common_log(LOG_INFO, 'Setting cache value for key ' . $key); $this->_items[$key] = $value; @@ -175,7 +171,6 @@ class Cache if (Event::handle('StartCacheDelete', array(&$key, &$success))) { if (array_key_exists($key, $this->_items[$key])) { - common_log(LOG_INFO, 'Deleting cache value for key ' . $key); unset($this->_items[$key]); } $success = true; -- cgit v1.2.3-54-g00ecf From 783a2e249bac2ccd02b6ae3351dfe83630b71cc0 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 4 Jan 2010 10:30:19 -0800 Subject: Fix for auto_increment parameter in auto-created tables via checkschema. Update FeedSub plugin for non-Plugin_DataObject setup and working checkschema updates. --- lib/columndef.php | 1 + lib/schema.php | 4 ++ plugins/FeedSub/FeedSubPlugin.php | 7 ++- plugins/FeedSub/feedinfo.php | 108 +++++++++++++++++++++++++++++--------- 4 files changed, 90 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/columndef.php b/lib/columndef.php index 1bae6b33b..ac2fcd23e 100644 --- a/lib/columndef.php +++ b/lib/columndef.php @@ -74,6 +74,7 @@ class ColumnDef * @param string $key type of key * @param value $default default value * @param value $extra unused + * @param boolean $auto_increment */ function __construct($name=null, $type=null, $size=null, diff --git a/lib/schema.php b/lib/schema.php index a8ba91b87..6fe442d56 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -523,6 +523,10 @@ class Schema } else { $sql .= ($cd->nullable) ? "null " : "not null "; } + + if (!empty($cd->auto_increment)) { + $sql .= " auto_increment "; + } return $sql; } diff --git a/plugins/FeedSub/FeedSubPlugin.php b/plugins/FeedSub/FeedSubPlugin.php index 857a9794d..e49e2a648 100644 --- a/plugins/FeedSub/FeedSubPlugin.php +++ b/plugins/FeedSub/FeedSubPlugin.php @@ -105,12 +105,11 @@ class FeedSubPlugin extends Plugin return true; } - /* - // auto increment seems to be broken function onCheckSchema() { + // warning: the autoincrement doesn't seem to set. + // alter table feedinfo change column id id int(11) not null auto_increment; $schema = Schema::get(); - $schema->ensureDataObject('Feedinfo'); + $schema->ensureTable('feedinfo', Feedinfo::schemaDef()); return true; } - */ } diff --git a/plugins/FeedSub/feedinfo.php b/plugins/FeedSub/feedinfo.php index fff66afe9..b166bd6e1 100644 --- a/plugins/FeedSub/feedinfo.php +++ b/plugins/FeedSub/feedinfo.php @@ -31,7 +31,7 @@ class FeedDBException extends FeedSubException } } -class Feedinfo extends Plugin_DataObject +class Feedinfo extends Memcached_DataObject { public $__table = 'feedinfo'; @@ -56,34 +56,90 @@ class Feedinfo extends Plugin_DataObject return parent::staticGet(__CLASS__, $k, $v); } - function tableDef() + /** + * return table definition for DB_DataObject + * + * DB_DataObject needs to know something about the table to manipulate + * instances. This method provides all the DB_DataObject needs to know. + * + * @return array array of column definitions + */ + + function table() + { + return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'feeduri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'homeuri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'huburi' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'verify_token' => DB_DATAOBJECT_STR, + 'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, + 'sub_end' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, + 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, + 'lastupdate' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); + } + + static function schemaDef() + { + return array(new ColumnDef('id', 'integer', + /*size*/ null, + /*nullable*/ false, + /*key*/ 'PRI', + /*default*/ '0', + /*extra*/ null, + /*auto_increment*/ true), + new ColumnDef('profile_id', 'integer', + null, false), + new ColumnDef('feeduri', 'varchar', + 255, false, 'UNI'), + new ColumnDef('homeuri', 'varchar', + 255, false), + new ColumnDef('huburi', 'varchar', + 255, false), + new ColumnDef('verify_token', 'varchar', + 32, true), + new ColumnDef('sub_start', 'datetime', + null, true), + new ColumnDef('sub_end', 'datetime', + null, true), + new ColumnDef('created', 'datetime', + null, false), + new ColumnDef('lastupdate', 'datetime', + null, false)); + } + + /** + * return key definitions for DB_DataObject + * + * DB_DataObject needs to know about keys that the table has; this function + * defines them. + * + * @return array key definitions + */ + + function keys() { - class_exists('Schema'); // autoload hack - // warning: the autoincrement doesn't seem to set. - // alter table feedinfo change column id id int(11) not null auto_increment; - return new TableDef($this->__table, - array(new ColumnDef('id', 'integer', - null, false, 'PRI', '0', null, true), - new ColumnDef('profile_id', 'integer', - null, false), - new ColumnDef('feeduri', 'varchar', - 255, false, 'UNI'), - new ColumnDef('homeuri', 'varchar', - 255, false), - new ColumnDef('huburi', 'varchar', - 255, false), - new ColumnDef('verify_token', 'varchar', - 32, true), - new ColumnDef('sub_start', 'datetime', - null, true), - new ColumnDef('sub_end', 'datetime', - null, true), - new ColumnDef('created', 'datetime', - null, false), - new ColumnDef('lastupdate', 'datetime', - null, false))); + return array('id' => 'P'); //? } + /** + * return key definitions for Memcached_DataObject + * + * Our caching system uses the same key definitions, but uses a different + * method to get them. + * + * @return array key definitions + */ + + function keyTypes() + { + return $this->keys(); + } + + /** + * Fetch the StatusNet-side profile for this feed + * @return Profile + */ public function getProfile() { return Profile::staticGet('id', $this->profile_id); -- cgit v1.2.3-54-g00ecf From 6911e1c7972c3adec53d0fe04ebdd7da0fbd8b12 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 4 Jan 2010 11:55:27 -0800 Subject: Ticket 2141: bugs with weighted popularity lists across year boundary. Consolidated several separate implementations of the same weighting algorithm into common_sql_weight() and fixed some bugs... For MySQL, now using timestampdiff() instead of subtraction for the comparison, so we get sane results when the year doesn't match, and utc_timestamp() rather than now() so we don't get negative ages for recent items with local server timezone. Unknown whether the same problems affect PostgreSQL, but note that it lacks the timestampdiff() SQL function. --- actions/favorited.php | 8 ++------ actions/publictagcloud.php | 11 ++++------- lib/grouptagcloudsection.php | 7 +------ lib/personaltagcloudsection.php | 11 +++-------- lib/popularnoticesection.php | 6 +++--- lib/util.php | 20 ++++++++++++++++++++ 6 files changed, 33 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/actions/favorited.php b/actions/favorited.php index 150b67b0b..9ffa5b844 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -185,11 +185,7 @@ class FavoritedAction extends Action function showContent() { - if (common_config('db', 'type') == 'pgsql') { - $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; - } else { - $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; - } + $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $qry = 'SELECT notice.*, '. $weightexpr . ' as weight ' . @@ -207,7 +203,7 @@ class FavoritedAction extends Action } $notice = Memcached_DataObject::cachedQuery('Notice', - sprintf($qry, common_config('popular', 'dropoff')), + $qry, 600); $nl = new NoticeList($notice, $this); diff --git a/actions/publictagcloud.php b/actions/publictagcloud.php index 5c7074029..b5b474f13 100644 --- a/actions/publictagcloud.php +++ b/actions/publictagcloud.php @@ -105,12 +105,8 @@ class PublictagcloudAction extends Action #Add the aggregated columns... $tags->selectAdd('max(notice_id) as last_notice_id'); - if(common_config('db','type')=='pgsql') { - $calc='sum(exp(-extract(epoch from (now()-created))/%s)) as weight'; - } else { - $calc='sum(exp(-(now() - created)/%s)) as weight'; - } - $tags->selectAdd(sprintf($calc, common_config('tag', 'dropoff'))); + $calc = common_sql_weight('created', common_config('tag', 'dropoff')); + $tags->selectAdd($calc . ' as weight'); $tags->groupBy('tag'); $tags->orderBy('weight DESC'); @@ -136,10 +132,11 @@ class PublictagcloudAction extends Action $this->elementStart('dd'); $this->elementStart('ul', 'tags xoxo tag-cloud'); foreach ($tw as $tag => $weight) { + common_log(LOG_DEBUG, "$weight/$sum"); if ($sum) { $weightedSum = $weight/$sum; } else { - $weightedSum = 1; + $weightedSum = 0.5; } $this->showTag($tag, $weight, $weightedSum); } diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php index 091cf4845..14ceda085 100644 --- a/lib/grouptagcloudsection.php +++ b/lib/grouptagcloudsection.php @@ -58,11 +58,7 @@ class GroupTagCloudSection extends TagCloudSection function getTags() { - if (common_config('db', 'type') == 'pgsql') { - $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; - } else { - $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; - } + $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); $names = $this->group->getAliases(); @@ -99,7 +95,6 @@ class GroupTagCloudSection extends TagCloudSection $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, - common_config('tag', 'dropoff'), $this->group->id, $namestring), 3600); diff --git a/lib/personaltagcloudsection.php b/lib/personaltagcloudsection.php index 0b29d58ca..091425f92 100644 --- a/lib/personaltagcloudsection.php +++ b/lib/personaltagcloudsection.php @@ -58,13 +58,9 @@ class PersonalTagCloudSection extends TagCloudSection function getTags() { - if (common_config('db', 'type') == 'pgsql') { - $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; - } else { - $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; - } - - $qry = 'SELECT notice_tag.tag, '. + $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); + + $qry = 'SELECT notice_tag.tag, '. $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . @@ -83,7 +79,6 @@ class PersonalTagCloudSection extends TagCloudSection $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, - common_config('tag', 'dropoff'), $this->user->id), 3600); return $tag; diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index 9fbc9d2dd..fbf9a60ab 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -48,17 +48,17 @@ class PopularNoticeSection extends NoticeSection { function getNotices() { + // @fixme there should be a common func for this if (common_config('db', 'type') == 'pgsql') { - $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; if (!empty($this->out->tag)) { $tag = pg_escape_string($this->out->tag); } } else { - $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; if (!empty($this->out->tag)) { $tag = mysql_escape_string($this->out->tag); } } + $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $qry = "SELECT notice.*, $weightexpr as weight "; if(isset($tag)) { $qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' . @@ -78,7 +78,7 @@ class PopularNoticeSection extends NoticeSection $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; $notice = Memcached_DataObject::cachedQuery('Notice', - sprintf($qry, common_config('popular', 'dropoff')), + $qry, 1200); return $notice; } diff --git a/lib/util.php b/lib/util.php index 63656b604..50bd0e2ac 100644 --- a/lib/util.php +++ b/lib/util.php @@ -908,6 +908,26 @@ function common_sql_date($datetime) return strftime('%Y-%m-%d %H:%M:%S', $datetime); } +/** + * Return an SQL fragment to calculate an age-based weight from a given + * timestamp or datetime column. + * + * @param string $column name of field we're comparing against current time + * @param integer $dropoff divisor for age in seconds before exponentiation + * @return string SQL fragment + */ +function common_sql_weight($column, $dropoff) +{ + if (common_config('db', 'type') == 'pgsql') { + // PostgreSQL doesn't support timestampdiff function. + // @fixme will this use the right time zone? + // @fixme does this handle cross-year subtraction correctly? + return "sum(exp(-extract(epoch from (now() - $column)) / $dropoff))"; + } else { + return "sum(exp(timestampdiff(second, utc_timestamp(), $column) / $dropoff))"; + } +} + function common_redirect($url, $code=307) { static $status = array(301 => "Moved Permanently", -- cgit v1.2.3-54-g00ecf From a1821ec8afd40c3ab88546a8fa2e6fc03a19ad25 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 4 Jan 2010 09:59:47 -1000 Subject: default value for cache::get() changed from null to false --- lib/cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index 253839fb1..bac3499e5 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -116,7 +116,7 @@ class Cache function get($key) { - $value = null; + $value = false; if (Event::handle('StartCacheGet', array(&$key, &$value))) { if (array_key_exists($key, $this->_items)) { -- cgit v1.2.3-54-g00ecf From 16254c14c8984f457b13c32d2b9bc0baedfde448 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 5 Jan 2010 09:54:43 -0800 Subject: Typo fix in the new default in-process cache; spewed notice warnings on deletion, breaking XHR responses. --- lib/cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/cache.php b/lib/cache.php index bac3499e5..85e8badc1 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -170,7 +170,7 @@ class Cache $success = false; if (Event::handle('StartCacheDelete', array(&$key, &$success))) { - if (array_key_exists($key, $this->_items[$key])) { + if (array_key_exists($key, $this->_items)) { unset($this->_items[$key]); } $success = true; -- 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 'lib') 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 'lib') 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 'lib') 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 9960ec2143445417a5f44f307b1dfbbd97194b45 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 9 Dec 2009 02:14:48 +0000 Subject: Support an 'extra' clause when definining a column (e.g.: 'on update CURRENT_TIMESTAMP'). --- lib/schema.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/schema.php b/lib/schema.php index 6fe442d56..a7f64ebed 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -528,6 +528,10 @@ class Schema $sql .= " auto_increment "; } + if (!empty($cd->extra)) { + $sql .= "{$cd->extra} "; + } + return $sql; } } -- cgit v1.2.3-54-g00ecf From 013e6dfdd481470cc02994b6db58a387a95016ca Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 6 Jan 2010 13:40:28 -0800 Subject: Don't output notices from deleted users. --- actions/twitapisearchatom.php | 9 ++++++++- lib/jsonsearchresultslist.php | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php index 1cb8d7efe..baed2a0c7 100644 --- a/actions/twitapisearchatom.php +++ b/actions/twitapisearchatom.php @@ -208,7 +208,14 @@ class TwitapisearchatomAction extends ApiAction $this->showFeed(); foreach ($notices as $n) { - $this->showEntry($n); + + $profile = $n->getProfile(); + + // Don't show notices from deleted users + + if (!empty($profile)) { + $this->showEntry($n); + } } $this->endAtom(); diff --git a/lib/jsonsearchresultslist.php b/lib/jsonsearchresultslist.php index 569bfa873..0d72ddf7a 100644 --- a/lib/jsonsearchresultslist.php +++ b/lib/jsonsearchresultslist.php @@ -105,8 +105,14 @@ class JSONSearchResultsList break; } - $item = new ResultItem($this->notice); - array_push($this->results, $item); + $profile = $this->notice->getProfile(); + + // Don't show notices from deleted users + + if (!empty($profile)) { + $item = new ResultItem($this->notice); + array_push($this->results, $item); + } } $time_end = microtime(true); -- cgit v1.2.3-54-g00ecf From 541053e84b2754e0d2c8b735c624383b6a126122 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 6 Jan 2010 17:08:01 -0500 Subject: The structure return by parse_url is an associative array, not an object. --- lib/htmloutputter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 2091c6e2c..31660ce95 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -352,7 +352,7 @@ class HTMLOutputter extends XMLOutputter { if(Event::handle('StartScriptElement', array($this,&$src,&$type))) { $url = parse_url($src); - if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment)) + if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) { $src = common_path($src) . '?version=' . STATUSNET_VERSION; } -- cgit v1.2.3-54-g00ecf From 5d9a2eb17e3f6e3bc73b5aa80625a365761b6689 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 6 Jan 2010 14:42:46 -0800 Subject: Ticket 2107: remove "not implemented" items from sms/xmpp help; nobody likes being told what they can't do! Also broke up the localized help message into line-by-line pieces to ease translation maintenance. --- doc-src/sms | 11 +-------- lib/command.php | 74 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 38 insertions(+), 47 deletions(-) (limited to 'lib') diff --git a/doc-src/sms b/doc-src/sms index 1a3064318..2c20921c3 100644 --- a/doc-src/sms +++ b/doc-src/sms @@ -56,13 +56,4 @@ You can use the following commands with %%site.name%%. * sub <nickname> - same as 'follow' * unsub <nickname> - same as 'leave' * last <nickname> - same as 'get' -* on <nickname> - not yet implemented. -* off <nickname> - not yet implemented. -* nudge <nickname> - not yet implemented. -* invite <phone number> - not yet implemented. -* track <word> - not yet implemented. -* untrack <word> - not yet implemented. -* track off - not yet implemented. -* untrack all - not yet implemented. -* tracks - not yet implemented. -* tracking - not yet implemented. +* nudge <nickname> - remind a user to update. diff --git a/lib/command.php b/lib/command.php index 67140c348..ad2e0bb97 100644 --- a/lib/command.php +++ b/lib/command.php @@ -742,42 +742,42 @@ class HelpCommand extends Command function execute($channel) { $channel->output($this->user, - _("Commands:\n". - "on - turn on notifications\n". - "off - turn off notifications\n". - "help - show this help\n". - "follow - subscribe to user\n". - "groups - lists the groups you have joined\n". - "subscriptions - list the people you follow\n". - "subscribers - list the people that follow you\n". - "leave - unsubscribe from user\n". - "d - direct message to user\n". - "get - get last notice from user\n". - "whois - get profile info on user\n". - "fav - add user's last notice as a 'fave'\n". - "fav # - add notice with the given id as a 'fave'\n". - "repeat # - repeat a notice with a given id\n". - "repeat - repeat the last notice from user\n". - "reply # - reply to notice with a given id\n". - "reply - reply to the last notice from user\n". - "join - join group\n". - "login - Get a link to login to the web interface\n". - "drop - leave group\n". - "stats - get your stats\n". - "stop - same as 'off'\n". - "quit - same as 'off'\n". - "sub - same as 'follow'\n". - "unsub - same as 'leave'\n". - "last - same as 'get'\n". - "on - not yet implemented.\n". - "off - not yet implemented.\n". - "nudge - remind a user to update.\n". - "invite - not yet implemented.\n". - "track - not yet implemented.\n". - "untrack - not yet implemented.\n". - "track off - not yet implemented.\n". - "untrack all - not yet implemented.\n". - "tracks - not yet implemented.\n". - "tracking - not yet implemented.\n")); + _("Commands:")."\n". + _("on - turn on notifications")."\n". + _("off - turn off notifications")."\n". + _("help - show this help")."\n". + _("follow - subscribe to user")."\n". + _("groups - lists the groups you have joined")."\n". + _("subscriptions - list the people you follow")."\n". + _("subscribers - list the people that follow you")."\n". + _("leave - unsubscribe from user")."\n". + _("d - direct message to user")."\n". + _("get - get last notice from user")."\n". + _("whois - get profile info on user")."\n". + _("fav - add user's last notice as a 'fave'")."\n". + _("fav # - add notice with the given id as a 'fave'")."\n". + _("repeat # - repeat a notice with a given id")."\n". + _("repeat - repeat the last notice from user")."\n". + _("reply # - reply to notice with a given id")."\n". + _("reply - reply to the last notice from user")."\n". + _("join - join group")."\n". + #_("login - Get a link to login to the web interface")."\n". + _("drop - leave group")."\n". + _("stats - get your stats")."\n". + _("stop - same as 'off'")."\n". + _("quit - same as 'off'")."\n". + _("sub - same as 'follow'")."\n". + _("unsub - same as 'leave'")."\n". + _("last - same as 'get'")."\n". + #_("on - not yet implemented.")."\n". + #_("off - not yet implemented.")."\n". + _("nudge - remind a user to update.")."\n"); + #_("invite - not yet implemented.")."\n". + #_("track - not yet implemented.")."\n". + #_("untrack - not yet implemented.")."\n". + #_("track off - not yet implemented.")."\n". + #_("untrack all - not yet implemented.")."\n". + #_("tracks - not yet implemented.")."\n". + #_("tracking - not yet implemented.")."\n" } } -- cgit v1.2.3-54-g00ecf From f4fa785fb7cf6f222f77ad81f6a1e50e5af7fdf3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 6 Jan 2010 23:24:24 -0800 Subject: Revert "Ticket 2107: remove "not implemented" items from sms/xmpp help; nobody likes being told what they can't do!" This reverts commit 5d9a2eb17e3f6e3bc73b5aa80625a365761b6689. These are commands that are/were implemented by Twitter, and we don't (yet) implemented. People will be looking for that information. --- doc-src/sms | 11 ++++++++- lib/command.php | 74 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 47 insertions(+), 38 deletions(-) (limited to 'lib') diff --git a/doc-src/sms b/doc-src/sms index 2c20921c3..1a3064318 100644 --- a/doc-src/sms +++ b/doc-src/sms @@ -56,4 +56,13 @@ You can use the following commands with %%site.name%%. * sub <nickname> - same as 'follow' * unsub <nickname> - same as 'leave' * last <nickname> - same as 'get' -* nudge <nickname> - remind a user to update. +* on <nickname> - not yet implemented. +* off <nickname> - not yet implemented. +* nudge <nickname> - not yet implemented. +* invite <phone number> - not yet implemented. +* track <word> - not yet implemented. +* untrack <word> - not yet implemented. +* track off - not yet implemented. +* untrack all - not yet implemented. +* tracks - not yet implemented. +* tracking - not yet implemented. diff --git a/lib/command.php b/lib/command.php index ad2e0bb97..67140c348 100644 --- a/lib/command.php +++ b/lib/command.php @@ -742,42 +742,42 @@ class HelpCommand extends Command function execute($channel) { $channel->output($this->user, - _("Commands:")."\n". - _("on - turn on notifications")."\n". - _("off - turn off notifications")."\n". - _("help - show this help")."\n". - _("follow - subscribe to user")."\n". - _("groups - lists the groups you have joined")."\n". - _("subscriptions - list the people you follow")."\n". - _("subscribers - list the people that follow you")."\n". - _("leave - unsubscribe from user")."\n". - _("d - direct message to user")."\n". - _("get - get last notice from user")."\n". - _("whois - get profile info on user")."\n". - _("fav - add user's last notice as a 'fave'")."\n". - _("fav # - add notice with the given id as a 'fave'")."\n". - _("repeat # - repeat a notice with a given id")."\n". - _("repeat - repeat the last notice from user")."\n". - _("reply # - reply to notice with a given id")."\n". - _("reply - reply to the last notice from user")."\n". - _("join - join group")."\n". - #_("login - Get a link to login to the web interface")."\n". - _("drop - leave group")."\n". - _("stats - get your stats")."\n". - _("stop - same as 'off'")."\n". - _("quit - same as 'off'")."\n". - _("sub - same as 'follow'")."\n". - _("unsub - same as 'leave'")."\n". - _("last - same as 'get'")."\n". - #_("on - not yet implemented.")."\n". - #_("off - not yet implemented.")."\n". - _("nudge - remind a user to update.")."\n"); - #_("invite - not yet implemented.")."\n". - #_("track - not yet implemented.")."\n". - #_("untrack - not yet implemented.")."\n". - #_("track off - not yet implemented.")."\n". - #_("untrack all - not yet implemented.")."\n". - #_("tracks - not yet implemented.")."\n". - #_("tracking - not yet implemented.")."\n" + _("Commands:\n". + "on - turn on notifications\n". + "off - turn off notifications\n". + "help - show this help\n". + "follow - subscribe to user\n". + "groups - lists the groups you have joined\n". + "subscriptions - list the people you follow\n". + "subscribers - list the people that follow you\n". + "leave - unsubscribe from user\n". + "d - direct message to user\n". + "get - get last notice from user\n". + "whois - get profile info on user\n". + "fav - add user's last notice as a 'fave'\n". + "fav # - add notice with the given id as a 'fave'\n". + "repeat # - repeat a notice with a given id\n". + "repeat - repeat the last notice from user\n". + "reply # - reply to notice with a given id\n". + "reply - reply to the last notice from user\n". + "join - join group\n". + "login - Get a link to login to the web interface\n". + "drop - leave group\n". + "stats - get your stats\n". + "stop - same as 'off'\n". + "quit - same as 'off'\n". + "sub - same as 'follow'\n". + "unsub - same as 'leave'\n". + "last - same as 'get'\n". + "on - not yet implemented.\n". + "off - not yet implemented.\n". + "nudge - remind a user to update.\n". + "invite - not yet implemented.\n". + "track - not yet implemented.\n". + "untrack - not yet implemented.\n". + "track off - not yet implemented.\n". + "untrack all - not yet implemented.\n". + "tracks - not yet implemented.\n". + "tracking - not yet implemented.\n")); } } -- 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 'lib') 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 From 14421d9db31392c731fc6d298805f6f4fd216b8b Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Thu, 7 Jan 2010 21:01:07 +0000 Subject: Correction to previous commit --- lib/jabber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/jabber.php b/lib/jabber.php index 6e094c207..a821856a8 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 == LOCAL_PUBLIC) { + if ($public && $notice->is_local == Notice::LOCAL_PUBLIC) { $profile = Profile::staticGet($notice->profile_id); if (!$profile) { -- cgit v1.2.3-54-g00ecf From 2c33e61b94fca8654c0d543fb0baa164ee86d2c3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 7 Jan 2010 16:13:36 -0800 Subject: add default plugins and load them --- lib/common.php | 21 +++++++++++++++++++++ lib/default.php | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'lib') diff --git a/lib/common.php b/lib/common.php index b0e5c4390..fb5e5919e 100644 --- a/lib/common.php +++ b/lib/common.php @@ -238,6 +238,27 @@ function __autoload($cls) } } +// Load default plugins + +foreach ($config['plugins']['default'] as $name => $params) { + if (is_null($params)) { + addPlugin($name); + } else if (is_array($params)) { + if (count($params) == 0) { + addPlugin($name); + } else { + $keys = array_keys($params); + if (is_string($keys[0])) { + addPlugin($name, $params); + } else { + foreach ($params as $paramset) { + addPlugin($name, $paramset); + } + } + } + } +} + // XXX: how many of these could be auto-loaded on use? // XXX: note that these files should not use config options // at compile time since DB config options are not yet loaded. diff --git a/lib/default.php b/lib/default.php index f2e577149..5acd2fb87 100644 --- a/lib/default.php +++ b/lib/default.php @@ -230,4 +230,21 @@ $default = array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates 'logincommand' => array('disabled' => true), + 'plugins' => + array('default' => array('LilUrl' => array('shortenerName'=>'ur1.ca', + 'freeService' => true, + 'serviceUrl'=>'http://ur1.ca/'), + 'PtitUrl' => array('shortenerName' => 'ptiturl1.com', + 'serviceUrl' => 'http://ptiturl.com/?creer=oui&action=Reduire&url=%1$s'), + 'SimpleUrl' => array(array('shortenerName' => 'is.gd', 'serviceUrl' => 'http://is.gd/api.php?longurl=%1$s'), + array('shortenerName' => 'snipr.com', 'serviceUrl' => 'http://snipr.com/site/snip?r=simple&link=%1$s'), + array('shortenerName' => 'metamark.net', 'serviceUrl' => 'http://metamark.net/api/rest/simple?long_url=%1$s'), + array('shortenerName' => 'tinyurl.com', 'serviceUrl' => 'http://tinyurl.com/api-create.php?url=%1$s')), + 'TightUrl' => array('shortenerName' => '2tu.us', 'freeService' => true,'serviceUrl'=>'http://2tu.us/?save=y&url=%1$s'), + 'Geonames' => null, + 'Mapstraction' => null, + 'Linkback' => null, + 'WikiHashtags' => null, + 'OpenID' => null), + ) ); -- cgit v1.2.3-54-g00ecf From 4a4ac7a1082405621ce8e578099ddb7be329bb38 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 7 Jan 2010 17:26:40 -0800 Subject: add a version action to give credit and list plugins --- actions/version.php | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/action.php | 2 + lib/router.php | 4 +- 3 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 actions/version.php (limited to 'lib') diff --git a/actions/version.php b/actions/version.php new file mode 100644 index 000000000..92a59ed47 --- /dev/null +++ b/actions/version.php @@ -0,0 +1,227 @@ +. + * + * @category Info + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Version info page + * + * A page that shows version information for this site. Helpful for + * debugging, for giving credit to authors, and for linking to more + * complete documentation for admins. + * + * @category Info + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +class VersionAction extends Action +{ + var $pluginVersions = array(); + + /** + * Return true since we're read-only. + * + * @param array $args other arguments + * + * @return boolean is read only action? + */ + + function isReadOnly($args) + { + return true; + } + + /** + * Returns the page title + * + * @return string page title + */ + + function title() + { + return sprintf(_("StatusNet %s"), STATUSNET_VERSION); + } + + /** + * Prepare to run + * + * Fire off an event to let plugins report their + * versions. + * + * @param array $args array misc. arguments + * + * @return boolean true + */ + + function prepare($args) + { + parent::prepare($args); + + Event::handle('PluginVersion', array(&$this->pluginVersions)); + + return true; + } + + /** + * Execute the action + * + * Shows a page with the version information in the + * content area. + * + * @param array $args ignored. + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showPage(); + } + + /** + * Show version information + * + * @return void + */ + + function showContent() + { + $this->elementStart('p'); + + $this->raw(sprintf(_('This site is powered by %s version %s, '. + 'Copyright 2008-2010 StatusNet, Inc. '. + 'and contributors.'), + XMLStringer::estring('a', array('href' => 'http://status.net/'), + _('StatusNet')), + STATUSNET_VERSION)); + $this->elementEnd('p'); + + $this->element('h2', null, _('Contributors')); + + $this->element('p', null, implode(', ', $this->contributors)); + + $this->element('h2', null, _('License')); + + $this->element('p', null, + _('StatusNet is free software: you can redistribute it and/or modify '. + 'it under the terms of the GNU Affero General Public License as published by '. + 'the Free Software Foundation, either version 3 of the License, or '. + '(at your option) any later version. ')); + + $this->element('p', null, + _('This program is distributed in the hope that it will be useful, '. + 'but WITHOUT ANY WARRANTY; without even the implied warranty of '. + 'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the '. + 'GNU Affero General Public License for more details. ')); + + $this->elementStart('p'); + $this->raw(sprintf(_('You should have received a copy of the GNU Affero General Public License '. + 'along with this program. If not, see %s.'), + XMLStringer::estring('a', array('href' => 'http://www.gnu.org/licenses/agpl.html'), + 'http://www.gnu.org/licenses/agpl.html'))); + $this->elementEnd('p'); + + // XXX: Theme information? + + if (count($this->pluginVersions)) { + $this->element('h2', null, _('Plugins')); + + foreach ($this->pluginVersions as $plugin) { + $this->elementStart('dl'); + $this->element('dt', null, _('Name')); + if (array_key_exists('homepage', $plugin)) { + $this->elementStart('dd'); + $this->element('a', array('href' => $plugin['homepage']), + $plugin['name']); + $this->elementEnd('dd'); + } else { + $this->element('dd', null, $plugin['name']); + } + $this->element('dt', null, _('Version')); + $this->element('dd', null, $plugin['version']); + if (array_key_exists('author', $plugin)) { + $this->element('dt', null, _('Author(s)')); + $this->element('dd', null, $plugin['author']); + } + if (array_key_exists('rawdescription', $plugin)) { + $this->element('dt', null, _('Description')); + $this->elementStart('dd'); + $this->raw($plugin['rawdescription']); + $this->elementEnd('dd'); + } else if (array_key_exists('description', $plugin)) { + $this->element('dt', null, _('Description')); + $this->element('dd', null, $plugin['description']); + } + $this->elementEnd('dl'); + } + } + + } + + var $contributors = array('Evan Prodromou (StatusNet)', + 'Zach Copley (StatusNet)', + 'Earle Martin (StatusNet)', + 'Marie-Claude Doyon (StatusNet)', + 'Sarven Capadisli (StatusNet)', + 'Robin Millette (StatusNet)', + 'Ciaran Gultnieks', + 'Michael Landers', + 'Ori Avtalion', + 'Garret Buell', + 'Mike Cochrane', + 'Matthew Gregg', + 'Florian Biree', + 'Erik Stambaugh', + 'drry', + 'Gina Haeussge', + 'Tryggvi Björgvinsson', + 'Adrian Lang', + 'Meitar Moscovitz', + 'Sean Murphy', + 'Leslie Michael Orchard', + 'Eric Helgeson', + 'Ken Sedgwick', + 'Brian Hendrickson', + 'Tobias Diekershoff', + 'Dan Moore', + 'Fil', + 'Jeff Mitchell', + 'Brenda Wallace', + 'Jeffery To', + 'Federico Marani', + 'Craig Andrews', + 'mEDI', + 'Brett Taylor'); +} diff --git a/lib/action.php b/lib/action.php index 35df03566..715072d1e 100644 --- a/lib/action.php +++ b/lib/action.php @@ -736,6 +736,8 @@ class Action extends HTMLOutputter // lawsuit _('Privacy')); $this->menuItem(common_local_url('doc', array('title' => 'source')), _('Source')); + $this->menuItem(common_local_url('version'), + _('Version')); $this->menuItem(common_local_url('doc', array('title' => 'contact')), _('Contact')); $this->menuItem(common_local_url('doc', array('title' => 'badge')), diff --git a/lib/router.php b/lib/router.php index 7ec962460..287d3c79f 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,9 @@ class Router 'silence', 'unsilence', 'repeat', 'deleteuser', - 'geocode'); + 'geocode', + 'version', + ); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); -- cgit v1.2.3-54-g00ecf From 9693b2cf2ff66cccc40497ac6b4c2dcc0f574ea2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 7 Jan 2010 17:33:46 -0800 Subject: add default plugin version information --- lib/plugin.php | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib') diff --git a/lib/plugin.php b/lib/plugin.php index de7313e59..65ccdafbb 100644 --- a/lib/plugin.php +++ b/lib/plugin.php @@ -104,5 +104,16 @@ class Plugin { $this->log(LOG_DEBUG, $msg); } + + function onPluginVersion(&$versions) + { + $cls = get_class($this); + $name = mb_substr($cls, 0, -6); + + $versions[] = array('name' => $name, + 'version' => _('Unknown')); + + return true; + } } -- cgit v1.2.3-54-g00ecf From 505cd382f3d0d37f3d9581a907877e644b5118fd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 7 Jan 2010 23:38:19 -0800 Subject: ptiturl.com correct name --- lib/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/default.php b/lib/default.php index 5acd2fb87..a52c05b53 100644 --- a/lib/default.php +++ b/lib/default.php @@ -234,7 +234,7 @@ $default = array('default' => array('LilUrl' => array('shortenerName'=>'ur1.ca', 'freeService' => true, 'serviceUrl'=>'http://ur1.ca/'), - 'PtitUrl' => array('shortenerName' => 'ptiturl1.com', + 'PtitUrl' => array('shortenerName' => 'ptiturl.com', 'serviceUrl' => 'http://ptiturl.com/?creer=oui&action=Reduire&url=%1$s'), 'SimpleUrl' => array(array('shortenerName' => 'is.gd', 'serviceUrl' => 'http://is.gd/api.php?longurl=%1$s'), array('shortenerName' => 'snipr.com', 'serviceUrl' => 'http://snipr.com/site/snip?r=simple&link=%1$s'), -- cgit v1.2.3-54-g00ecf From 2aa0ab9777a1b2a0eec5946dede56e23daa0defe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 8 Jan 2010 01:00:29 -0800 Subject: let system administrators disallow certain admin panels --- lib/adminpanelaction.php | 46 +++++++++++++++++++++++++++++++++++----------- lib/default.php | 4 +++- 2 files changed, 38 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/adminpanelaction.php b/lib/adminpanelaction.php index 7997eb2b1..a6981ac61 100644 --- a/lib/adminpanelaction.php +++ b/lib/adminpanelaction.php @@ -70,7 +70,7 @@ class AdminPanelAction extends Action if (!common_logged_in()) { $this->clientError(_('Not logged in.')); - return; + return false; } $user = common_current_user(); @@ -94,7 +94,18 @@ class AdminPanelAction extends Action if (!$user->hasRight(Right::CONFIGURESITE)) { $this->clientError(_('You cannot make changes to this site.')); - return; + return false; + } + + // This panel must be enabled + + $name = $this->trimmed('action'); + + $name = mb_substr($name, 0, -10); + + if (!in_array($name, common_config('admin', 'panels'))) { + $this->clientError(_('Changes to that panel are not allowed.'), 403); + return false; } return true; @@ -224,7 +235,7 @@ class AdminPanelAction extends Action $this->clientError(_('saveSettings() not implemented.')); return; } - + /** * Delete a design setting * @@ -296,20 +307,33 @@ class AdminPanelNav extends Widget if (Event::handle('StartAdminPanelNav', array($this))) { - $this->out->menuItem(common_local_url('siteadminpanel'), _('Site'), - _('Basic site configuration'), $action_name == 'siteadminpanel', 'nav_site_admin_panel'); + if ($this->canAdmin('site')) { + $this->out->menuItem(common_local_url('siteadminpanel'), _('Site'), + _('Basic site configuration'), $action_name == 'siteadminpanel', 'nav_site_admin_panel'); + } - $this->out->menuItem(common_local_url('designadminpanel'), _('Design'), - _('Design configuration'), $action_name == 'designadminpanel', 'nav_design_admin_panel'); + if ($this->canAdmin('design')) { + $this->out->menuItem(common_local_url('designadminpanel'), _('Design'), + _('Design configuration'), $action_name == 'designadminpanel', 'nav_design_admin_panel'); + } - $this->out->menuItem(common_local_url('useradminpanel'), _('User'), - _('Paths configuration'), $action_name == 'useradminpanel', 'nav_design_admin_panel'); + if ($this->canAdmin('user')) { + $this->out->menuItem(common_local_url('useradminpanel'), _('User'), + _('Paths configuration'), $action_name == 'useradminpanel', 'nav_design_admin_panel'); + } - $this->out->menuItem(common_local_url('pathsadminpanel'), _('Paths'), - _('Paths configuration'), $action_name == 'pathsadminpanel', 'nav_design_admin_panel'); + if ($this->canAdmin('paths')) { + $this->out->menuItem(common_local_url('pathsadminpanel'), _('Paths'), + _('Paths configuration'), $action_name == 'pathsadminpanel', 'nav_design_admin_panel'); + } Event::handle('EndAdminPanelNav', array($this)); } $this->action->elementEnd('ul'); } + + function canAdmin($name) + { + return in_array($name, common_config('admin', 'panels')); + } } diff --git a/lib/default.php b/lib/default.php index a52c05b53..fa862f3ff 100644 --- a/lib/default.php +++ b/lib/default.php @@ -246,5 +246,7 @@ $default = 'Linkback' => null, 'WikiHashtags' => null, 'OpenID' => null), - ) + ), + 'admin' => + array('panels' => array('design', 'site', 'user', 'paths')), ); -- cgit v1.2.3-54-g00ecf From 0fcd91cf1e33f4f908d7b2acc2772afaab0821ec Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 8 Jan 2010 13:26:48 +0000 Subject: Using json2.js --- lib/action.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index 715072d1e..1b4cb5cec 100644 --- a/lib/action.php +++ b/lib/action.php @@ -253,6 +253,7 @@ class Action extends HTMLOutputter // lawsuit $this->script('js/jquery.min.js'); $this->script('js/jquery.form.js'); $this->script('js/jquery.cookie.js'); + $this->script('js/json2.js'); $this->script('js/jquery.joverlay.min.js'); Event::handle('EndShowJQueryScripts', array($this)); } -- cgit v1.2.3-54-g00ecf From 54c18e68dadc37174e8631db76dae064a88920a6 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 8 Jan 2010 13:58:23 +0000 Subject: Some code cleaning for geo UI --- js/util.js | 42 ++++++++++++++++++++---------------------- lib/noticeform.php | 2 +- theme/base/css/display.css | 10 +++++----- theme/default/css/display.css | 6 +++--- theme/identica/css/display.css | 6 +++--- 5 files changed, 32 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/js/util.js b/js/util.js index a29b158be..9c6342ffe 100644 --- a/js/util.js +++ b/js/util.js @@ -51,8 +51,7 @@ var SN = { // StatusNet NoticeLon: 'notice_data-lon', NoticeLocationId: 'notice_data-location_id', NoticeLocationNs: 'notice_data-location_ns', - NoticeLocationName: 'notice_data-location_name', - NoticeLocationCookieName: 'location_enabled', + NoticeGeoName: 'notice_data-geo_name', NoticeDataGeo: 'notice_data-geo', NoticeDataGeoSelected: 'notice_data-geo_selected' } @@ -460,7 +459,7 @@ var SN = { // StatusNet var NLon = $('#'+SN.C.S.NoticeLon).val(); var NLNS = $('#'+SN.C.S.NoticeLocationNs).val(); var NLID = $('#'+SN.C.S.NoticeLocationId).val(); - var NLN = $('#'+SN.C.S.NoticeLocationName).text(); + var NLN = $('#'+SN.C.S.NoticeGeoName).text(); var NDGe = $('#'+SN.C.S.NoticeDataGeo); function removeNoticeDataGeo() { @@ -473,7 +472,7 @@ var SN = { // StatusNet $('#'+SN.C.S.NoticeLocationId).val(''); $('#'+SN.C.S.NoticeDataGeo).attr('checked', false); - $.cookie(SN.C.S.NoticeLocationCookieName, 'disabled'); + $.cookie(SN.C.S.NoticeDataGeo, 'disabled'); } function getJSONgeocodeURL(geocodeURL, data) { @@ -497,10 +496,10 @@ var SN = { // StatusNet NLN_text = location.name; } - $('#'+SN.C.S.NoticeLocationName) - .replaceWith('
'); + $('#'+SN.C.S.NoticeGeoName) + .replaceWith(''); - $('#'+SN.C.S.NoticeLocationName) + $('#'+SN.C.S.NoticeGeoName) .attr('href', location.url) .text(NLN_text) .click(function() { @@ -524,32 +523,31 @@ var SN = { // StatusNet 'NLNU': location.url, 'NDG': true }; - $.cookie(SN.C.S.NoticeLocationCookieName, JSON.stringify(cookieValue)); + $.cookie(SN.C.S.NoticeDataGeo, JSON.stringify(cookieValue)); }); } if (NDGe.length > 0) { - var cookieValue = $.cookie(SN.C.S.NoticeLocationCookieName); - if (cookieValue == 'disabled') { + if ($.cookie(SN.C.S.NoticeDataGeo) == 'disabled') { NDGe.attr('checked', false); } else { NDGe.attr('checked', true); } - var NLE = $('#notice_data-location_wrap'); - var geocodeURL = NLE.attr('title'); - NLE.removeAttr('title'); + var NGW = $('#notice_data-geo_wrap'); + var geocodeURL = NGW.attr('title'); + NGW.removeAttr('title'); $('label[for='+SN.C.S.NoticeDataGeo+']').attr('title', jQuery.trim($('label[for='+SN.C.S.NoticeDataGeo+']').text())); NDGe.change(function() { - var NLN = $('#'+SN.C.S.NoticeLocationName); + var NLN = $('#'+SN.C.S.NoticeGeoName); if (NLN.length > 0) { NLN.remove(); } - if ($('#'+SN.C.S.NoticeDataGeo).attr('checked') === true || $.cookie(SN.C.S.NoticeLocationCookieName) === null) { + if ($('#'+SN.C.S.NoticeDataGeo).attr('checked') === true || $.cookie(SN.C.S.NoticeDataGeo) === null) { $('label[for='+SN.C.S.NoticeDataGeo+']').addClass('checked'); var S = '
'; @@ -563,9 +561,9 @@ var SN = { // StatusNet } NDGS = $('#'+SN.C.S.NoticeDataGeoSelected); - NDGS.prepend('Geo '); + NDGS.prepend('Geo '); - var NLN = $('#'+SN.C.S.NoticeLocationName); + var NLN = $('#'+SN.C.S.NoticeGeoName); NLN.addClass('processing'); $('#'+SN.C.S.NoticeDataGeoSelected+' button.close').click(function(){ @@ -582,7 +580,7 @@ var SN = { // StatusNet return false; }); - if ($.cookie(SN.C.S.NoticeLocationCookieName) === null || $.cookie(SN.C.S.NoticeLocationCookieName) == 'disabled') { + if ($.cookie(SN.C.S.NoticeDataGeo) === null || $.cookie(SN.C.S.NoticeDataGeo) == 'disabled') { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( function(position) { @@ -623,17 +621,17 @@ var SN = { // StatusNet } } else { - var cookieValue = JSON.parse($.cookie(SN.C.S.NoticeLocationCookieName)); + var cookieValue = JSON.parse($.cookie(SN.C.S.NoticeDataGeo)); $('#'+SN.C.S.NoticeLat).val(cookieValue.NLat); $('#'+SN.C.S.NoticeLon).val(cookieValue.NLon); $('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS); $('#'+SN.C.S.NoticeLocationId).val(cookieValue.NLID); $('#'+SN.C.S.NoticeDataGeo).attr('checked', cookieValue.NDG); - $('#'+SN.C.S.NoticeLocationName) - .replaceWith(''); + $('#'+SN.C.S.NoticeGeoName) + .replaceWith(''); - $('#'+SN.C.S.NoticeLocationName) + $('#'+SN.C.S.NoticeGeoName) .attr('href', cookieValue.NLNU) .text(cookieValue.NLN) .click(function() { diff --git a/lib/noticeform.php b/lib/noticeform.php index 99865645a..ddfe45055 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -207,7 +207,7 @@ class NoticeForm extends Form $this->out->hidden('notice_data-location_id', empty($this->location_id) ? (empty($this->profile->location_id) ? null : $this->profile->location_id) : $this->location_id, 'location_id'); $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns'); - $this->out->elementStart('div', array('id' => 'notice_data-location_wrap', + $this->out->elementStart('div', array('id' => 'notice_data-geo_wrap', 'title' => common_local_url('geocode'))); $this->out->checkbox('notice_data-geo', _('Share your location'), true); $this->out->elementEnd('div'); diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 2031aed21..cdacb9a62 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -555,7 +555,7 @@ margin-bottom:0; line-height:1.618; } .form_notice #notice_data-attach_selected code, -.form_notice #notice_data-location_name { +.form_notice #notice_data-geo_name { float:left; width:80%; display:block; @@ -575,7 +575,7 @@ font-size:0.8em; float:left; } -.form_notice #notice_data-location_wrap label { +.form_notice #notice_data-geo_wrap label { position:absolute; top:25px; right:4px; @@ -585,16 +585,16 @@ width:16px; height:16px; display:block; } -.form_notice #notice_data-location_wrap input { +.form_notice #notice_data-geo_wrap input { display:none; } -.form_notice #notice_data-location_wrap label { +.form_notice #notice_data-geo_wrap label { font-weight:normal; font-size:1em; margin-bottom:0; text-indent:-9999px; } -.form_notice #notice_data-location_name { +.form_notice #notice_data-geo_name { display:block; padding-left:21px; } diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 1fe2bd569..2360976e5 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -111,10 +111,10 @@ box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1); text-shadow:none; } -.form_notice span#notice_data-location_name { +.form_notice span#notice_data-geo_name { background-position:0 47%; } -.form_notice a#notice_data-location_name { +.form_notice a#notice_data-geo_name { background-position:0 -1711px; } .form_notice label[for=notice_data-geo] { @@ -192,7 +192,7 @@ button.close, .entity_silence input.submit, .entity_delete input.submit, .notice-options .repeated, -.form_notice a#notice_data-location_name, +.form_notice a#notice_data-geo_name, .form_notice label[for=notice_data-geo], button.minimize { background-image:url(../../base/images/icons/icons-01.gif); diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index dd02de6b9..91af1d8ec 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -111,10 +111,10 @@ box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1); text-shadow:none; } -.form_notice span#notice_data-location_name { +.form_notice span#notice_data-geo_name { background-position:0 47%; } -.form_notice a#notice_data-location_name { +.form_notice a#notice_data-geo_name { background-position:0 -1711px; } .form_notice label[for=notice_data-geo] { @@ -192,7 +192,7 @@ button.close, .entity_silence input.submit, .entity_delete input.submit, .notice-options .repeated, -.form_notice a#notice_data-location_name, +.form_notice a#notice_data-geo_name, .form_notice label[for=notice_data-geo], button.minimize { background-image:url(../../base/images/icons/icons-01.gif); -- cgit v1.2.3-54-g00ecf From 8901e01692e6010a371a4aa2e5a9b3649e0bcc2f Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 8 Jan 2010 18:07:02 +0000 Subject: Added i18n text for @title values in geo sharing actions --- js/util.js | 6 +++--- lib/noticeform.php | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/js/util.js b/js/util.js index 4e588a3b6..0314668d9 100644 --- a/js/util.js +++ b/js/util.js @@ -480,7 +480,7 @@ var SN = { // StatusNet var NDGe = $('#'+SN.C.S.NoticeDataGeo); function removeNoticeDataGeo() { - $('label[for='+SN.C.S.NoticeDataGeo+']').removeClass('checked'); + $('label[for='+SN.C.S.NoticeDataGeo+']').removeClass('checked').attr('title', jQuery.trim($('label[for='+SN.C.S.NoticeDataGeo+']').text())); $('#'+SN.C.S.NoticeDataGeoSelected).hide(); $('#'+SN.C.S.NoticeLat).val(''); @@ -566,7 +566,7 @@ var SN = { // StatusNet } if ($('#'+SN.C.S.NoticeDataGeo).attr('checked') === true || $.cookie(SN.C.S.NoticeDataGeoCookie) === null) { - $('label[for='+SN.C.S.NoticeDataGeo+']').addClass('checked'); + $('label[for='+SN.C.S.NoticeDataGeo+']').addClass('checked').attr('title', NoticeDataGeoShareDisable_text); var S = '
'; var NDGS = $('#'+SN.C.S.NoticeDataGeoSelected); @@ -579,7 +579,7 @@ var SN = { // StatusNet } NDGS = $('#'+SN.C.S.NoticeDataGeoSelected); - NDGS.prepend('Geo '); + NDGS.prepend('Geo '); var NLN = $('#'+SN.C.S.NoticeGeoName); NLN.addClass('processing'); diff --git a/lib/noticeform.php b/lib/noticeform.php index ddfe45055..f0b704e87 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -209,8 +209,10 @@ class NoticeForm extends Form $this->out->elementStart('div', array('id' => 'notice_data-geo_wrap', 'title' => common_local_url('geocode'))); - $this->out->checkbox('notice_data-geo', _('Share your location'), true); + $this->out->checkbox('notice_data-geo', _('Share my location'), true); $this->out->elementEnd('div'); + $this->out->inlineScript(' var NoticeDataGeoShareDisable_text = "'._('Do not share my location.').'";'. + ' var NoticeDataGeoInfoMinimize_text = "'._('Hide this info').'";'); } Event::handle('EndShowNoticeFormData', array($this)); -- cgit v1.2.3-54-g00ecf From 055f3fdddb998bfee1a6f6e61d1ca6df4b2fb740 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Fri, 8 Jan 2010 18:52:09 -0500 Subject: Add an IMAP daemon so StatusNet can process incoming user posts via catch-all mailbox (in addition to the pre-existing script alias method) --- lib/mailhandler.php | 275 ++++++++++++++++++++++++++++++++++++++++++++ plugins/Imap/ImapPlugin.php | 85 ++++++++++++++ plugins/Imap/README | 32 ++++++ plugins/Imap/imapdaemon.php | 147 +++++++++++++++++++++++ scripts/maildaemon.php | 263 +----------------------------------------- 5 files changed, 542 insertions(+), 260 deletions(-) create mode 100644 lib/mailhandler.php create mode 100644 plugins/Imap/ImapPlugin.php create mode 100644 plugins/Imap/README create mode 100755 plugins/Imap/imapdaemon.php (limited to 'lib') diff --git a/lib/mailhandler.php b/lib/mailhandler.php new file mode 100644 index 000000000..32a8cd9bc --- /dev/null +++ b/lib/mailhandler.php @@ -0,0 +1,275 @@ +. + */ + +require_once(INSTALLDIR . '/lib/mail.php'); +require_once(INSTALLDIR . '/lib/mediafile.php'); +require_once('Mail/mimeDecode.php'); + +# FIXME: we use both Mail_mimeDecode and mailparse +# Need to move everything to mailparse + +class MailHandler +{ + function __construct() + { + } + + function handle_message($rawmessage) + { + list($from, $to, $msg, $attachments) = $this->parse_message($rawmessage); + if (!$from || !$to || !$msg) { + $this->error(null, _('Could not parse message.')); + } + common_log(LOG_INFO, "Mail from $from to $to with ".count($attachments) .' attachment(s): ' .substr($msg, 0, 20)); + $user = $this->user_from_header($from); + if (!$user) { + $this->error($from, _('Not a registered user.')); + return false; + } + if (!$this->user_match_to($user, $to)) { + $this->error($from, _('Sorry, that is not your incoming email address.')); + return false; + } + if (!$user->emailpost) { + $this->error($from, _('Sorry, no incoming email allowed.')); + return false; + } + $response = $this->handle_command($user, $from, $msg); + if ($response) { + return true; + } + $msg = $this->cleanup_msg($msg); + $msg = common_shorten_links($msg); + if (Notice::contentTooLong($msg)) { + $this->error($from, sprintf(_('That\'s too long. '. + 'Max notice size is %d chars.'), + Notice::maxContent())); + } + + $mediafiles = array(); + + foreach($attachments as $attachment){ + + $mf = null; + + try { + $mf = MediaFile::fromFileHandle($attachment, $user); + } catch(ClientException $ce) { + $this->error($from, $ce->getMessage()); + } + + $msg .= ' ' . $mf->shortUrl(); + + array_push($mediafiles, $mf); + fclose($attachment); + } + + $err = $this->add_notice($user, $msg, $mediafiles); + + if (is_string($err)) { + $this->error($from, $err); + return false; + } else { + return true; + } + } + + function error($from, $msg) + { + file_put_contents("php://stderr", $msg . "\n"); + exit(1); + } + + function user_from_header($from_hdr) + { + $froms = mailparse_rfc822_parse_addresses($from_hdr); + if (!$froms) { + return null; + } + $from = $froms[0]; + $addr = common_canonical_email($from['address']); + $user = User::staticGet('email', $addr); + if (!$user) { + $user = User::staticGet('smsemail', $addr); + } + return $user; + } + + function user_match_to($user, $to_hdr) + { + $incoming = $user->incomingemail; + $tos = mailparse_rfc822_parse_addresses($to_hdr); + foreach ($tos as $to) { + if (strcasecmp($incoming, $to['address']) == 0) { + return true; + } + } + return false; + } + + function handle_command($user, $from, $msg) + { + $inter = new CommandInterpreter(); + $cmd = $inter->handle_command($user, $msg); + if ($cmd) { + $cmd->execute(new MailChannel($from)); + return true; + } + return false; + } + + function respond($from, $to, $response) + { + + $headers['From'] = $to; + $headers['To'] = $from; + $headers['Subject'] = "Command complete"; + + return mail_send(array($from), $headers, $response); + } + + function log($level, $msg) + { + common_log($level, 'MailDaemon: '.$msg); + } + + function add_notice($user, $msg, $mediafiles) + { + try { + $notice = Notice::saveNew($user->id, $msg, 'mail'); + } catch (Exception $e) { + $this->log(LOG_ERR, $e->getMessage()); + return $e->getMessage(); + } + foreach($mediafiles as $mf){ + $mf->attachToNotice($notice); + } + common_broadcast_notice($notice); + $this->log(LOG_INFO, + 'Added notice ' . $notice->id . ' from user ' . $user->nickname); + return true; + } + + function parse_message($contents) + { + $parsed = Mail_mimeDecode::decode(array('input' => $contents, + 'include_bodies' => true, + 'decode_headers' => true, + 'decode_bodies' => true)); + if (!$parsed) { + return null; + } + + $from = $parsed->headers['from']; + + $to = $parsed->headers['to']; + + $type = $parsed->ctype_primary . '/' . $parsed->ctype_secondary; + + $attachments = array(); + + $this->extract_part($parsed,$msg,$attachments); + + return array($from, $to, $msg, $attachments); + } + + function extract_part($parsed,&$msg,&$attachments){ + if ($parsed->ctype_primary == 'multipart') { + if($parsed->ctype_secondary == 'alternative'){ + $altmsg = $this->extract_msg_from_multipart_alternative_part($parsed); + if(!empty($altmsg)) $msg = $altmsg; + }else{ + foreach($parsed->parts as $part){ + $this->extract_part($part,$msg,$attachments); + } + } + } else if ($parsed->ctype_primary == 'text' + && $parsed->ctype_secondary=='plain') { + $msg = $parsed->body; + if(strtolower($parsed->ctype_parameters['charset']) != "utf-8"){ + $msg = utf8_encode($msg); + } + }else if(!empty($parsed->body)){ + if(common_config('attachments', 'uploads')){ + //only save attachments if uploads are enabled + $attachment = tmpfile(); + fwrite($attachment, $parsed->body); + $attachments[] = $attachment; + } + } + } + + function extract_msg_from_multipart_alternative_part($parsed){ + foreach ($parsed->parts as $part) { + $this->extract_part($part,$msg,$attachments); + } + //we don't want any attachments that are a result of this parsing + return $msg; + } + + function unsupported_type($type) + { + $this->error(null, "Unsupported message type: " . $type); + } + + function cleanup_msg($msg) + { + $lines = explode("\n", $msg); + + $output = ''; + + foreach ($lines as $line) { + // skip quotes + if (preg_match('/^\s*>.*$/', $line)) { + continue; + } + // skip start of quote + if (preg_match('/^\s*On.*wrote:\s*$/', $line)) { + continue; + } + // probably interesting to someone, not us + if (preg_match('/^\s*Sent via/', $line)) { + continue; + } + if (preg_match('/^\s*Sent from my/', $line)) { + continue; + } + + // skip everything after a sig + if (preg_match('/^\s*--+\s*$/', $line) || + preg_match('/^\s*__+\s*$/', $line)) + { + break; + } + // skip everything after Outlook quote + if (preg_match('/^\s*-+\s*Original Message\s*-+\s*$/', $line)) { + break; + } + // skip everything after weird forward + if (preg_match('/^\s*Begin\s+forward/', $line)) { + break; + } + + $output .= ' ' . $line; + } + + preg_replace('/\s+/', ' ', $output); + return trim($output); + } +} diff --git a/plugins/Imap/ImapPlugin.php b/plugins/Imap/ImapPlugin.php new file mode 100644 index 000000000..034444222 --- /dev/null +++ b/plugins/Imap/ImapPlugin.php @@ -0,0 +1,85 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * IMAP plugin to allow StatusNet to grab incoming emails and handle them as new user posts + * + * @category Plugin + * @package StatusNet + * @author Craig Andrews mailbox)){ + throw new Exception("must specify a mailbox"); + } + if(!isset($this->user)){ + throw new Exception("must specify a user"); + } + if(!isset($this->password)){ + throw new Exception("must specify a password"); + } + if(!isset($this->poll_frequency)){ + throw new Exception("must specify a poll_frequency"); + } + + self::$instances[] = $this; + return true; + } + + function cleanup(){ + $index = array_search($this, self::$instances); + unset(self::$instances[$index]); + return true; + } + + function onGetValidDaemons($daemons) + { + if(! self::$daemon_added){ + array_push($daemons, INSTALLDIR . + '/plugins/Imap/imapdaemon.php'); + self::$daemon_added = true; + } + return true; + } +} diff --git a/plugins/Imap/README b/plugins/Imap/README new file mode 100644 index 000000000..640a411a8 --- /dev/null +++ b/plugins/Imap/README @@ -0,0 +1,32 @@ +The IMAP plugin allows for StatusNet to check a POP or IMAP mailbox for +incoming mail containing user posts. + +Installation +============ +addPlugin('imap', array( + 'mailbox' => '...', + 'user' => '...', + 'password' => '...' +)); +to the bottom of your config.php + +Also, make sure: +$config['mail']['domain'] = 'yourdomain.example.net'; +is set in your config.php + +Create a catch-all account for your domain, and use this account with this +plugin. Whenever a user sends a message to their personal notice posting +address, the message should end up in this mailbox, and then the plugin daemon +will pick it up and post the notice on the user's behalf. + +The daemon included with this plugin must be running. It will be started by +the plugin along with their other daemons when you run scripts/startdaemons.sh. +See the StatusNet README for more about queuing and daemons. + +Settings +======== +mailbox*: the mailbox specifier. + See http://www.php.net/manual/en/function.imap-open.php for details +user*: username to use when authenticating to the mailbox +password*: password to use when authenticating to the mailbox +poll_frequency: how often (in seconds) to check for new messages diff --git a/plugins/Imap/imapdaemon.php b/plugins/Imap/imapdaemon.php new file mode 100755 index 000000000..a45c603ce --- /dev/null +++ b/plugins/Imap/imapdaemon.php @@ -0,0 +1,147 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..')); + +$shortoptions = 'fi::'; +$longoptions = array('id::', 'foreground'); + +$helptext = <<$value) + { + $this->$attr = $value; + } + + $this->log(LOG_INFO, "INITIALIZE IMAPDaemon {" . $this->name() . "}"); + } + + function name() + { + return strtolower('imapdaemon.'.$this->user.'.'.crc32($this->mailbox)); + } + + function run() + { + $this->connect(); + while(true) + { + if(imap_ping($this->conn) || $this->connect()) + { + $this->check_mailbox(); + } + sleep($this->poll_frequency); + } + } + + function check_mailbox() + { + $count = imap_num_msg($this->conn); + $this->log(LOG_INFO, "Found $count messages"); + if($count > 0){ + $handler = new IMAPMailHandler(); + for($i=1; $i <= $count; $i++) + { + $rawmessage = imap_fetchheader($this->conn, $count, FT_PREFETCHTEXT) . imap_body($this->conn, $i); + $handler->handle_message($rawmessage); + imap_delete($this->conn, $i); + } + imap_expunge($this->conn); + $this->log(LOG_INFO, "Finished processing messages"); + } + } + + function log($level, $msg) + { + $text = $this->name() . ': '.$msg; + common_log($level, $text); + if (!$this->daemonize) + { + $line = common_log_line($level, $text); + echo $line; + echo "\n"; + } + } + + function connect() + { + $this->conn = imap_open($this->mailbox, $this->user, $this->password); + if($this->conn){ + $this->log(LOG_INFO, "Connected"); + return true; + }else{ + $this->log(LOG_INFO, "Failed to connect: " . imap_last_error()); + return false; + } + } +} + +class IMAPMailHandler extends MailHandler +{ + function error($from, $msg) + { + $this->log(LOG_INFO, "Error: $from $msg"); + $headers['To'] = $from; + $headers['Subject'] = "Error"; + + return mail_send(array($from), $headers, $msg); + } +} + +if (have_option('i', 'id')) { + $id = get_option_value('i', 'id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} + +$foreground = have_option('f', 'foreground'); + +foreach(ImapPlugin::$instances as $pluginInstance){ + + $daemon = new IMAPDaemon($id, !$foreground, array( + 'mailbox' => $pluginInstance->mailbox, + 'user' => $pluginInstance->user, + 'password' => $pluginInstance->password, + 'poll_frequency' => $pluginInstance->poll_frequency + )); + + $daemon->runOnce(); + +} diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php index b4e4d9f08..3b1ef96a1 100755 --- a/scripts/maildaemon.php +++ b/scripts/maildaemon.php @@ -27,266 +27,9 @@ as STDIN. END_OF_HELP; require_once INSTALLDIR.'/scripts/commandline.inc'; - -require_once(INSTALLDIR . '/lib/mail.php'); -require_once(INSTALLDIR . '/lib/mediafile.php'); -require_once('Mail/mimeDecode.php'); - -# FIXME: we use both Mail_mimeDecode and mailparse -# Need to move everything to mailparse - -class MailerDaemon -{ - function __construct() - { - } - - function handle_message($fname='php://stdin') - { - list($from, $to, $msg, $attachments) = $this->parse_message($fname); - if (!$from || !$to || !$msg) { - $this->error(null, _('Could not parse message.')); - } - common_log(LOG_INFO, "Mail from $from to $to with ".count($attachments) .' attachment(s): ' .substr($msg, 0, 20)); - $user = $this->user_from($from); - if (!$user) { - $this->error($from, _('Not a registered user.')); - return false; - } - if (!$this->user_match_to($user, $to)) { - $this->error($from, _('Sorry, that is not your incoming email address.')); - return false; - } - if (!$user->emailpost) { - $this->error($from, _('Sorry, no incoming email allowed.')); - return false; - } - $response = $this->handle_command($user, $from, $msg); - if ($response) { - return true; - } - $msg = $this->cleanup_msg($msg); - $msg = common_shorten_links($msg); - if (Notice::contentTooLong($msg)) { - $this->error($from, sprintf(_('That\'s too long. '. - 'Max notice size is %d chars.'), - Notice::maxContent())); - } - - $mediafiles = array(); - - foreach($attachments as $attachment){ - - $mf = null; - - try { - $mf = MediaFile::fromFileHandle($attachment, $user); - } catch(ClientException $ce) { - $this->error($from, $ce->getMessage()); - } - - $msg .= ' ' . $mf->shortUrl(); - - array_push($mediafiles, $mf); - fclose($attachment); - } - - $err = $this->add_notice($user, $msg, $mediafiles); - - if (is_string($err)) { - $this->error($from, $err); - return false; - } else { - return true; - } - } - - function error($from, $msg) - { - file_put_contents("php://stderr", $msg . "\n"); - exit(1); - } - - function user_from($from_hdr) - { - $froms = mailparse_rfc822_parse_addresses($from_hdr); - if (!$froms) { - return null; - } - $from = $froms[0]; - $addr = common_canonical_email($from['address']); - $user = User::staticGet('email', $addr); - if (!$user) { - $user = User::staticGet('smsemail', $addr); - } - return $user; - } - - function user_match_to($user, $to_hdr) - { - $incoming = $user->incomingemail; - $tos = mailparse_rfc822_parse_addresses($to_hdr); - foreach ($tos as $to) { - if (strcasecmp($incoming, $to['address']) == 0) { - return true; - } - } - return false; - } - - function handle_command($user, $from, $msg) - { - $inter = new CommandInterpreter(); - $cmd = $inter->handle_command($user, $msg); - if ($cmd) { - $cmd->execute(new MailChannel($from)); - return true; - } - return false; - } - - function respond($from, $to, $response) - { - - $headers['From'] = $to; - $headers['To'] = $from; - $headers['Subject'] = "Command complete"; - - return mail_send(array($from), $headers, $response); - } - - function log($level, $msg) - { - common_log($level, 'MailDaemon: '.$msg); - } - - function add_notice($user, $msg, $mediafiles) - { - try { - $notice = Notice::saveNew($user->id, $msg, 'mail'); - } catch (Exception $e) { - $this->log(LOG_ERR, $e->getMessage()); - return $e->getMessage(); - } - foreach($mediafiles as $mf){ - $mf->attachToNotice($notice); - } - common_broadcast_notice($notice); - $this->log(LOG_INFO, - 'Added notice ' . $notice->id . ' from user ' . $user->nickname); - return true; - } - - function parse_message($fname) - { - $contents = file_get_contents($fname); - $parsed = Mail_mimeDecode::decode(array('input' => $contents, - 'include_bodies' => true, - 'decode_headers' => true, - 'decode_bodies' => true)); - if (!$parsed) { - return null; - } - - $from = $parsed->headers['from']; - - $to = $parsed->headers['to']; - - $type = $parsed->ctype_primary . '/' . $parsed->ctype_secondary; - - $attachments = array(); - - $this->extract_part($parsed,$msg,$attachments); - - return array($from, $to, $msg, $attachments); - } - - function extract_part($parsed,&$msg,&$attachments){ - if ($parsed->ctype_primary == 'multipart') { - if($parsed->ctype_secondary == 'alternative'){ - $altmsg = $this->extract_msg_from_multipart_alternative_part($parsed); - if(!empty($altmsg)) $msg = $altmsg; - }else{ - foreach($parsed->parts as $part){ - $this->extract_part($part,$msg,$attachments); - } - } - } else if ($parsed->ctype_primary == 'text' - && $parsed->ctype_secondary=='plain') { - $msg = $parsed->body; - if(strtolower($parsed->ctype_parameters['charset']) != "utf-8"){ - $msg = utf8_encode($msg); - } - }else if(!empty($parsed->body)){ - if(common_config('attachments', 'uploads')){ - //only save attachments if uploads are enabled - $attachment = tmpfile(); - fwrite($attachment, $parsed->body); - $attachments[] = $attachment; - } - } - } - - function extract_msg_from_multipart_alternative_part($parsed){ - foreach ($parsed->parts as $part) { - $this->extract_part($part,$msg,$attachments); - } - //we don't want any attachments that are a result of this parsing - return $msg; - } - - function unsupported_type($type) - { - $this->error(null, "Unsupported message type: " . $type); - } - - function cleanup_msg($msg) - { - $lines = explode("\n", $msg); - - $output = ''; - - foreach ($lines as $line) { - // skip quotes - if (preg_match('/^\s*>.*$/', $line)) { - continue; - } - // skip start of quote - if (preg_match('/^\s*On.*wrote:\s*$/', $line)) { - continue; - } - // probably interesting to someone, not us - if (preg_match('/^\s*Sent via/', $line)) { - continue; - } - if (preg_match('/^\s*Sent from my/', $line)) { - continue; - } - - // skip everything after a sig - if (preg_match('/^\s*--+\s*$/', $line) || - preg_match('/^\s*__+\s*$/', $line)) - { - break; - } - // skip everything after Outlook quote - if (preg_match('/^\s*-+\s*Original Message\s*-+\s*$/', $line)) { - break; - } - // skip everything after weird forward - if (preg_match('/^\s*Begin\s+forward/', $line)) { - break; - } - - $output .= ' ' . $line; - } - - preg_replace('/\s+/', ' ', $output); - return trim($output); - } -} +require_once INSTALLDIR.'/lib/mailhandler.php'; if (common_config('emailpost', 'enabled')) { - $md = new MailerDaemon(); - $md->handle_message('php://stdin'); + $mh = new MailHandler(); + $mh->handle_message(file_get_contents('php://stdin')); } -- cgit v1.2.3-54-g00ecf