From 6da59fab58b3f517a9e48204faa4f29ceabc4ba9 Mon Sep 17 00:00:00 2001 From: James Walker Date: Tue, 18 May 2010 10:09:16 -0400 Subject: invalid mbox_sha1sum in the case where users don't have an email address (reported by pedantic-web.org) --- actions/foaf.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/actions/foaf.php b/actions/foaf.php index 9cb65a885..2f054de0c 100644 --- a/actions/foaf.php +++ b/actions/foaf.php @@ -95,7 +95,9 @@ class FoafAction extends Action // Would be nice to tell if they were a Person or not (e.g. a #person usertag?) $this->elementStart('Agent', array('rdf:about' => $this->user->uri)); - $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email)); + if ($this->user->email) { + $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email)); + } if ($this->profile->fullname) { $this->element('name', null, $this->profile->fullname); } -- cgit v1.2.3-54-g00ecf From 7c828ae5f8ab20f0daa8a1482fadce9b3e858975 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 18 May 2010 10:39:56 -0700 Subject: OpenID access control options: trusted provider URL, Launchpad team restrictions. Added an admin panel for setting these and OpenID-only mode, off by default. To enable the admin panel: $config['admin']['panels'][] = 'openid'; Or to set them manually: $config['openid']['trusted_provider'] = 'https://login.ubuntu.net/'; $config['openid']['required_team'] = 'my-project-cabal'; $config['site']['openidonly'] = true; OpenID-only mode can still be set from addPlugin() parameters as well for backwards compatibility. Note: if it's set there, that value will override the setting from the database or config.php. Note that team restrictions are only really meaningful if a trusted provider is set; otherwise, any OpenID server could report back that users are members of the given team. Restrictions are checked only at OpenID authentication time and will not kick off people currently with a session open; existing remembered logins may also survive these changes. Using code for Launchpad team support provided by Canonical under AGPLv3, pulled from r27 of WordPress teams integration plugin: https://code.edge.launchpad.net/~canonical-isd-hackers/wordpress-teams-integration/trunk --- plugins/OpenID/OpenIDPlugin.php | 67 ++++++-- plugins/OpenID/extlib/README | 6 + plugins/OpenID/extlib/teams-extension.php | 175 +++++++++++++++++++ plugins/OpenID/finishaddopenid.php | 6 + plugins/OpenID/finishopenidlogin.php | 6 + plugins/OpenID/openid.php | 36 ++++ plugins/OpenID/openidadminpanel.php | 270 ++++++++++++++++++++++++++++++ plugins/OpenID/openidlogin.php | 22 ++- plugins/OpenID/openidsettings.php | 70 ++++---- 9 files changed, 611 insertions(+), 47 deletions(-) create mode 100644 plugins/OpenID/extlib/README create mode 100644 plugins/OpenID/extlib/teams-extension.php create mode 100644 plugins/OpenID/openidadminpanel.php diff --git a/plugins/OpenID/OpenIDPlugin.php b/plugins/OpenID/OpenIDPlugin.php index 270e2c624..9eac9f6fc 100644 --- a/plugins/OpenID/OpenIDPlugin.php +++ b/plugins/OpenID/OpenIDPlugin.php @@ -20,7 +20,7 @@ * @category Plugin * @package StatusNet * @author Evan Prodromou - * @copyright 2009 StatusNet, Inc. + * @copyright 2009-2010 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/ */ @@ -45,7 +45,19 @@ if (!defined('STATUSNET')) { class OpenIDPlugin extends Plugin { - public $openidOnly = false; + // Plugin parameter: set true to disallow non-OpenID logins + // If set, overrides the setting in database or $config['site']['openidonly'] + public $openidOnly = null; + + function initialize() + { + parent::initialize(); + if ($this->openidOnly !== null) { + global $config; + $config['site']['openidonly'] = (bool)$this->openidOnly; + } + + } /** * Add OpenID-related paths to the router table @@ -67,6 +79,7 @@ class OpenIDPlugin extends Plugin $m->connect('index.php?action=finishaddopenid', array('action' => 'finishaddopenid')); $m->connect('main/openidserver', array('action' => 'openidserver')); + $m->connect('admin/openid', array('action' => 'openidadminpanel')); return true; } @@ -84,7 +97,7 @@ class OpenIDPlugin extends Plugin function onStartConnectPath(&$path, &$defaults, &$rules, &$result) { - if ($this->openidOnly) { + if (common_config('site', 'openidonly')) { static $block = array('main/login', 'main/register', 'main/recoverpassword', @@ -108,7 +121,7 @@ class OpenIDPlugin extends Plugin function onArgsInitialize($args) { - if ($this->openidOnly) { + if (common_config('site', 'openidonly')) { if (array_key_exists('action', $args)) { $action = trim($args['action']); if (in_array($action, array('login', 'register'))) { @@ -199,7 +212,7 @@ class OpenIDPlugin extends Plugin function onStartPrimaryNav($action) { - if ($this->openidOnly && !common_logged_in()) { + if (common_config('site', 'openidonly') && !common_logged_in()) { // TRANS: Tooltip for main menu option "Login" $tooltip = _m('TOOLTIP', 'Login to the site'); // TRANS: Main menu option when not logged in to log in @@ -241,7 +254,7 @@ class OpenIDPlugin extends Plugin function onStartLoginGroupNav(&$action) { - if ($this->openidOnly) { + if (common_config('site', 'openidonly')) { $this->showOpenIDLoginTab($action); // Even though we replace this code, we // DON'T run the End* hook, to keep others from @@ -297,7 +310,7 @@ class OpenIDPlugin extends Plugin */ function onStartAccountSettingsPasswordMenuItem($menu, &$unused) { - if ($this->openidOnly) { + if (common_config('site', 'openidonly')) { return false; } return true; @@ -345,13 +358,19 @@ class OpenIDPlugin extends Plugin case 'OpenidsettingsAction': case 'OpenidserverAction': case 'OpenidtrustAction': - require_once INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; + case 'OpenidadminpanelAction': + require_once dirname(__FILE__) . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; case 'User_openid': - require_once INSTALLDIR.'/plugins/OpenID/User_openid.php'; + require_once dirname(__FILE__) . '/User_openid.php'; return false; case 'User_openid_trustroot': - require_once INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php'; + require_once dirname(__FILE__) . '/User_openid_trustroot.php'; + return false; + case 'Auth_OpenID_TeamsExtension': + case 'Auth_OpenID_TeamsRequest': + case 'Auth_OpenID_TeamsResponse': + require_once dirname(__FILE__) . '/extlib/teams-extension.php'; return false; default: return true; @@ -442,7 +461,7 @@ class OpenIDPlugin extends Plugin function onRedirectToLogin($action, $user) { - if ($this->openidOnly || (!empty($user) && User_openid::hasOpenID($user->id))) { + if (common_config('site', 'openid_only') || (!empty($user) && User_openid::hasOpenID($user->id))) { common_redirect(common_local_url('openidlogin'), 303); return false; } @@ -577,6 +596,32 @@ class OpenIDPlugin extends Plugin return true; } + /** + * Add an OpenID tab to the admin panel + * + * @param Widget $nav Admin panel nav + * + * @return boolean hook value + */ + + function onEndAdminPanelNav($nav) + { + if (AdminPanelAction::canAdmin('openid')) { + + $action_name = $nav->action->trimmed('action'); + + $nav->out->menuItem( + common_local_url('openidadminpanel'), + _m('OpenID'), + _m('OpenID configuration'), + $action_name == 'openidadminpanel', + 'nav_openid_admin_panel' + ); + } + + return true; + } + /** * Add our version information to output * diff --git a/plugins/OpenID/extlib/README b/plugins/OpenID/extlib/README new file mode 100644 index 000000000..1fe80d79b --- /dev/null +++ b/plugins/OpenID/extlib/README @@ -0,0 +1,6 @@ +team-extension.php + Support for Launchpad's OpenID Teams extension + Maintainer: Canonical + Source: https://code.edge.launchpad.net/wordpress-teams-integration + r27 2010-04-27 + License: AGPLv3 diff --git a/plugins/OpenID/extlib/teams-extension.php b/plugins/OpenID/extlib/teams-extension.php new file mode 100644 index 000000000..451f2fb19 --- /dev/null +++ b/plugins/OpenID/extlib/teams-extension.php @@ -0,0 +1,175 @@ +. + */ + +/** + * Provides an example OpenID extension to query user team/group membership + * + * This code is based on code supplied with the openid library for simple + * registration data. + */ + +/** + * Require the Message implementation. + */ +require_once 'Auth/OpenID/Message.php'; +require_once 'Auth/OpenID/Extension.php'; + +/** + * The team/group extension base class + */ +class Auth_OpenID_TeamsExtension extends Auth_OpenID_Extension { + var $ns_uri = 'http://ns.launchpad.net/2007/openid-teams'; + var $ns_alias = 'lp'; + var $request_field = 'query_membership'; + var $response_field = 'is_member'; + + /** + * Get the string arguments that should be added to an OpenID + * message for this extension. + */ + function getExtensionArgs() { + $args = array(); + + if ($this->_teams) { + $args[$this->request_field] = implode(',', $this->_teams); + } + + return $args; + } + + /** + * Add the arguments from this extension to the provided message. + * + * Returns the message with the extension arguments added. + */ + function toMessage(&$message) { + if ($message->namespaces->addAlias($this->ns_uri, $this->ns_alias) === null) { + if ($message->namespaces->getAlias($this->ns_uri) != $this->ns_alias) { + return null; + } + } + + $message->updateArgs($this->ns_uri, $this->getExtensionArgs()); + return $message; + } + + /** + * Extract the team/group namespace URI from the given OpenID message. + * Handles OpenID 1 and 2. + * + * $message: The OpenID message from which to parse team/group data. + * This may be a request or response message. + * + * Returns the sreg namespace URI for the supplied message. + * + * @access private + */ + function _getExtensionNS(&$message) { + $alias = null; + $found_ns_uri = null; + + // See if there exists an alias for the namespace + $alias = $message->namespaces->getAlias($this->ns_uri); + + if ($alias !== null) { + $found_ns_uri = $this->ns_uri; + } + + if ($alias === null) { + // There is no alias for this extension, so try to add one. + $found_ns_uri = Auth_OpenID_TYPE_1_0; + + if ($message->namespaces->addAlias($this->ns_uri, $this->ns_alias) === null) { + // An alias for the string 'lp' already exists, but + // it's defined for something other than team/group membership + return null; + } + } + + return $found_ns_uri; + } +} + +/** + * The team/group extension request class + */ +class Auth_OpenID_TeamsRequest extends Auth_OpenID_TeamsExtension { + function __init($teams) { + if (!is_array($teams)) { + if (!empty($teams)) { + $teams = explode(',', $teams); + } else { + $teams = Array(); + } + } + + $this->_teams = $teams; + } + + function Auth_OpenID_TeamsRequest($teams) { + $this->__init($teams); + } +} + +/** + * The team/group extension response class + */ +class Auth_OpenID_TeamsResponse extends Auth_OpenID_TeamsExtension { + var $_teams = array(); + + function __init(&$resp, $signed_only=true) { + $this->ns_uri = $this->_getExtensionNS($resp->message); + + if ($signed_only) { + $args = $resp->getSignedNS($this->ns_uri); + } else { + $args = $resp->message->getArgs($this->ns_uri); + } + + if ($args === null) { + return null; + } + + // An OpenID 2.0 response will handle the namespaces + if (in_array($this->response_field, array_keys($args)) && !empty($args[$this->response_field])) { + $this->_teams = explode(',', $args[$this->response_field]); + } + + // Piggybacking on a 1.x request, however, won't so the field name will + // be different + elseif (in_array($this->ns_alias.'.'.$this->response_field, array_keys($args)) && !empty($args[$this->ns_alias.'.'.$this->response_field])) { + $this->_teams = explode(',', $args[$this->ns_alias.'.'.$this->response_field]); + } + } + + function Auth_OpenID_TeamsResponse(&$resp, $signed_only=true) { + $this->__init($resp, $signed_only); + } + + /** + * Get the array of teams the user is a member of + * + * @return array + */ + function getTeams() { + return $this->_teams; + } +} + +?> diff --git a/plugins/OpenID/finishaddopenid.php b/plugins/OpenID/finishaddopenid.php index 991e6584e..df1763a52 100644 --- a/plugins/OpenID/finishaddopenid.php +++ b/plugins/OpenID/finishaddopenid.php @@ -103,6 +103,12 @@ class FinishaddopenidAction extends Action $sreg = $sreg_resp->contents(); } + // Launchpad teams extension + if (!oid_check_teams($response)) { + $this->message(_m('OpenID authentication aborted: you are not allowed to login to this site.')); + return; + } + $cur = common_current_user(); $other = oid_get_user($canonical); diff --git a/plugins/OpenID/finishopenidlogin.php b/plugins/OpenID/finishopenidlogin.php index 32b092a0b..57723ff97 100644 --- a/plugins/OpenID/finishopenidlogin.php +++ b/plugins/OpenID/finishopenidlogin.php @@ -177,6 +177,12 @@ class FinishopenidloginAction extends Action $sreg = $sreg_resp->contents(); } + // Launchpad teams extension + if (!oid_check_teams($response)) { + $this->message(_m('OpenID authentication aborted: you are not allowed to login to this site.')); + return; + } + $user = oid_get_user($canonical); if ($user) { diff --git a/plugins/OpenID/openid.php b/plugins/OpenID/openid.php index 4ec336e1c..5ee9343d2 100644 --- a/plugins/OpenID/openid.php +++ b/plugins/OpenID/openid.php @@ -164,6 +164,15 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) $auth_request->addExtension($sreg_request); } + $requiredTeam = common_config('openid', 'required_team'); + if ($requiredTeam) { + // LaunchPad OpenID extension + $team_request = new Auth_OpenID_TeamsRequest(array($requiredTeam)); + if ($team_request) { + $auth_request->addExtension($team_request); + } + } + $trust_root = common_root_url(true); $process_url = common_local_url($returnto); @@ -286,6 +295,33 @@ function oid_assert_allowed($url) return; } +/** + * Check the teams available in the given OpenID response + * Using Launchpad's OpenID teams extension + * + * @return boolean whether this user is acceptable + */ +function oid_check_teams($response) +{ + $requiredTeam = common_config('openid', 'required_team'); + if ($requiredTeam) { + $team_resp = new Auth_OpenID_TeamsResponse($response); + if ($team_resp) { + $teams = $team_resp->getTeams(); + } else { + $teams = array(); + } + + $match = in_array($requiredTeam, $teams); + $is = $match ? 'is' : 'is not'; + common_log(LOG_DEBUG, "Remote user $is in required team $requiredTeam: [" . implode(', ', $teams) . "]"); + + return $match; + } + + return true; +} + class AutosubmitAction extends Action { var $form_html = null; diff --git a/plugins/OpenID/openidadminpanel.php b/plugins/OpenID/openidadminpanel.php new file mode 100644 index 000000000..063306366 --- /dev/null +++ b/plugins/OpenID/openidadminpanel.php @@ -0,0 +1,270 @@ +. + * + * @category Settings + * @package StatusNet + * @author Zach Copley + * @copyright 2010 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); +} + +/** + * Administer global OpenID settings + * + * @category Admin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class OpenidadminpanelAction extends AdminPanelAction +{ + /** + * Returns the page title + * + * @return string page title + */ + + function title() + { + return _m('OpenID'); + } + + /** + * Instructions for using this form. + * + * @return string instructions + */ + + function getInstructions() + { + return _m('OpenID settings'); + } + + /** + * Show the OpenID admin panel form + * + * @return void + */ + + function showForm() + { + $form = new OpenIDAdminPanelForm($this); + $form->show(); + return; + } + + /** + * Save settings from the form + * + * @return void + */ + + function saveSettings() + { + static $settings = array( + 'openid' => array('trusted_provider', 'required_team') + ); + + static $booleans = array( + 'site' => array('openidonly') + ); + + $values = array(); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = $this->trimmed($setting); + } + } + + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = ($this->boolean($setting)) ? 1 : 0; + } + } + + // This throws an exception on validation errors + + $this->validate($values); + + // assert(all values are valid); + + $config = new Config(); + + $config->query('BEGIN'); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + $config->query('COMMIT'); + + return; + } + + function validate(&$values) + { + // Validate consumer key and secret (can't be too long) + + if (mb_strlen($values['openid']['trusted_provider']) > 255) { + $this->clientError( + _m("Invalid provider URL. Max length is 255 characters.") + ); + } + + if (mb_strlen($values['openid']['required_team']) > 255) { + $this->clientError( + _m("Invalid team name. Max length is 255 characters.") + ); + } + } +} + +class OpenIDAdminPanelForm extends AdminForm +{ + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'openidadminpanel'; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_settings'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('openidadminpanel'); + } + + /** + * Data elements of the form + * + * @return void + * + * @todo Some of the options could prevent users from logging in again. + * Make sure that the acting administrator has a valid OpenID matching, + * or more carefully warn folks. + */ + + function formData() + { + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_openid') + ); + $this->out->element('legend', null, _m('Trusted provider')); + $this->out->element('p', 'form_guide', + _m('By default, users are allowed to authenticate with any OpenID provider. ' . + 'If you are using your own OpenID service for shared sign-in, ' . + 'you can restrict access to only your own users here.')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->input( + 'trusted_provider', + _m('Provider URL'), + _m('All OpenID logins will be sent to this URL; other providers may not be used.'), + 'openid' + ); + $this->unli(); + + $this->li(); + $this->input( + 'required_team', + _m('Required team'), + _m('Only allow logins from users in the given team (Launchpad extension).'), + 'openid' + ); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_openid-options') + ); + $this->out->element('legend', null, _m('Options')); + + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + + $this->out->checkbox( + 'openidonly', _m('Enable OpenID-only mode'), + (bool) $this->value('openidonly', 'site'), + _m('Require all users to login via OpenID. WARNING: disables password authentication for all users!'), + 'true' + ); + $this->unli(); + + $this->out->elementEnd('ul'); + + $this->out->elementEnd('fieldset'); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Save'), 'submit', null, _m('Save OpenID settings')); + } +} diff --git a/plugins/OpenID/openidlogin.php b/plugins/OpenID/openidlogin.php index 2a743672c..8c559c934 100644 --- a/plugins/OpenID/openidlogin.php +++ b/plugins/OpenID/openidlogin.php @@ -29,7 +29,12 @@ class OpenidloginAction extends Action if (common_is_real_login()) { $this->clientError(_m('Already logged in.')); } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $openid_url = $this->trimmed('openid_url'); + $provider = common_config('openid', 'trusted_provider'); + if ($provider) { + $openid_url = $provider; + } else { + $openid_url = $this->trimmed('openid_url'); + } oid_assert_allowed($openid_url); @@ -116,9 +121,18 @@ class OpenidloginAction extends Action $this->elementStart('ul', 'form_data'); $this->elementStart('li'); - $this->input('openid_url', _m('OpenID URL'), - $this->openid_url, - _m('Your OpenID URL')); + $provider = common_config('openid', 'trusted_provider'); + if ($provider) { + $this->element('label', array(), _m('OpenID provider')); + $this->element('span', array(), $provider); + $this->element('p', 'form_guide', + _m('You will be sent to the provider\'s site for authentication.')); + $this->hidden('openid_url', $provider); + } else { + $this->input('openid_url', _m('OpenID URL'), + $this->openid_url, + _m('Your OpenID URL')); + } $this->elementEnd('li'); $this->elementStart('li', array('id' => 'settings_rememberme')); $this->checkbox('rememberme', _m('Remember me'), false, diff --git a/plugins/OpenID/openidsettings.php b/plugins/OpenID/openidsettings.php index 16142cf48..505e7d0ee 100644 --- a/plugins/OpenID/openidsettings.php +++ b/plugins/OpenID/openidsettings.php @@ -90,34 +90,36 @@ class OpenidsettingsAction extends AccountSettingsAction { $user = common_current_user(); - $this->elementStart('form', array('method' => 'post', - 'id' => 'form_settings_openid_add', - 'class' => 'form_settings', - 'action' => - common_local_url('openidsettings'))); - $this->elementStart('fieldset', array('id' => 'settings_openid_add')); - $this->element('legend', null, _m('Add OpenID')); - $this->hidden('token', common_session_token()); - $this->element('p', 'form_guide', - _m('If you want to add an OpenID to your account, ' . - 'enter it in the box below and click "Add".')); - $this->elementStart('ul', 'form_data'); - $this->elementStart('li'); - $this->element('label', array('for' => 'openid_url'), - _m('OpenID URL')); - $this->element('input', array('name' => 'openid_url', - 'type' => 'text', - 'id' => 'openid_url')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - $this->element('input', array('type' => 'submit', - 'id' => 'settings_openid_add_action-submit', - 'name' => 'add', - 'class' => 'submit', - 'value' => _m('Add'))); - $this->elementEnd('fieldset'); - $this->elementEnd('form'); - + if (!common_config('openid', 'trusted_provider')) { + $this->elementStart('form', array('method' => 'post', + 'id' => 'form_settings_openid_add', + 'class' => 'form_settings', + 'action' => + common_local_url('openidsettings'))); + $this->elementStart('fieldset', array('id' => 'settings_openid_add')); + + $this->element('legend', null, _m('Add OpenID')); + $this->hidden('token', common_session_token()); + $this->element('p', 'form_guide', + _m('If you want to add an OpenID to your account, ' . + 'enter it in the box below and click "Add".')); + $this->elementStart('ul', 'form_data'); + $this->elementStart('li'); + $this->element('label', array('for' => 'openid_url'), + _m('OpenID URL')); + $this->element('input', array('name' => 'openid_url', + 'type' => 'text', + 'id' => 'openid_url')); + $this->elementEnd('li'); + $this->elementEnd('ul'); + $this->element('input', array('type' => 'submit', + 'id' => 'settings_openid_add_action-submit', + 'name' => 'add', + 'class' => 'submit', + 'value' => _m('Add'))); + $this->elementEnd('fieldset'); + $this->elementEnd('form'); + } $oid = new User_openid(); $oid->user_id = $user->id; @@ -234,10 +236,14 @@ class OpenidsettingsAction extends AccountSettingsAction } if ($this->arg('add')) { - $result = oid_authenticate($this->trimmed('openid_url'), - 'finishaddopenid'); - if (is_string($result)) { // error message - $this->showForm($result); + if (common_config('openid', 'trusted_provider')) { + $this->showForm(_m("Can't add new providers.")); + } else { + $result = oid_authenticate($this->trimmed('openid_url'), + 'finishaddopenid'); + if (is_string($result)) { // error message + $this->showForm($result); + } } } else if ($this->arg('remove')) { $this->removeOpenid(); -- cgit v1.2.3-54-g00ecf From 206229875511d24a97a0aac79605f6868d21ee7f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 21 May 2010 14:07:59 -0700 Subject: Add $config['queue']['stomp_enqueue_to'] override for which queue server to send to. Must be set to a value that matches one of the entries in $config['queue']['stomp_server'] array, otherwise ignored. --- lib/stompqueuemanager.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php index 5d5c7ccfb..de4ba7f01 100644 --- a/lib/stompqueuemanager.php +++ b/lib/stompqueuemanager.php @@ -122,7 +122,19 @@ class StompQueueManager extends QueueManager public function enqueue($object, $queue) { $this->_connect(); - return $this->_doEnqueue($object, $queue, $this->defaultIdx); + if (common_config('queue', 'stomp_enqueue_on')) { + // We're trying to force all writes to a single server. + // WARNING: this might do odd things if that server connection dies. + $idx = array_search(common_config('queue', 'stomp_enqueue_on'), + $this->servers); + if ($idx === false) { + common_log(LOG_ERR, 'queue stomp_enqueue_on setting does not match our server list.'); + $idx = $this->defaultIdx; + } + } else { + $idx = $this->defaultIdx; + } + return $this->_doEnqueue($object, $queue, $idx); } /** -- cgit v1.2.3-54-g00ecf From dc22ed84807555f6a16c041c16b3bc607c6587d8 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 22 May 2010 17:43:56 -0700 Subject: Hotpatch for Facebook mirror problems: drop messages when hitting rate limit (err 341) instead of retrying forever. On unknown errors, now throwing an exception so it'll hit the message retry limits. --- plugins/Facebook/facebookutil.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index ab2d42726..045891649 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -158,9 +158,22 @@ function facebookBroadcastNotice($notice) remove_facebook_app($flink); - } else { + } else if ($code == 341) { + // 341 Feed action request limit reached - Unable to update Facebook status + // Reposting immediately probably won't work, so drop the message for now. :( + + common_log(LOG_ERR, "Facebook rate limit hit: dropping notice $notice->id"); + return true; + } else { // Try sending again later. + // + // @fixme at the moment, returning false here could lead to an infinite loop + // if the error condition isn't actually transitory. + // + // Temporarily throwing an exception to kill the process so it'll hit our + // retry limits. + throw new Exception("Facebook error $code on notice $notice->id"); return false; } -- cgit v1.2.3-54-g00ecf From f7add6f25f37780fde2269b254c237caea9ef98d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 24 May 2010 07:47:15 -0700 Subject: Handle funky notice deletion cases more gracefully: if we already have a deleted_notice entry, don't freak out when we try to save it again on the second try. --- classes/Notice.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index e173a2469..d85c8cd33 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -97,15 +97,20 @@ class Notice extends Memcached_DataObject // For auditing purposes, save a record that the notice // was deleted. - $deleted = new Deleted_notice(); + // @fixme we have some cases where things get re-run and so the + // insert fails. + $deleted = Deleted_notice::staticGet('id', $this->id); + if (!$deleted) { + $deleted = new Deleted_notice(); - $deleted->id = $this->id; - $deleted->profile_id = $this->profile_id; - $deleted->uri = $this->uri; - $deleted->created = $this->created; - $deleted->deleted = common_sql_now(); + $deleted->id = $this->id; + $deleted->profile_id = $this->profile_id; + $deleted->uri = $this->uri; + $deleted->created = $this->created; + $deleted->deleted = common_sql_now(); - $deleted->insert(); + $deleted->insert(); + } // Clear related records -- cgit v1.2.3-54-g00ecf From 8d8751472766d1d6b0f89616152503ad35f65ab0 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 21 May 2010 05:03:23 +0000 Subject: Upgrade to latest old REST API library (0.1.0) --- plugins/Facebook/facebook/facebook.php | 74 +++++++++++----------- .../Facebook/facebook/facebookapi_php5_restlib.php | 56 ++-------------- 2 files changed, 42 insertions(+), 88 deletions(-) diff --git a/plugins/Facebook/facebook/facebook.php b/plugins/Facebook/facebook/facebook.php index 440706cbc..76696c1d5 100644 --- a/plugins/Facebook/facebook/facebook.php +++ b/plugins/Facebook/facebook/facebook.php @@ -45,7 +45,9 @@ class Facebook { public $user; public $profile_user; public $canvas_user; + public $ext_perms = array(); protected $base_domain; + /* * Create a Facebook client like this: * @@ -104,17 +106,17 @@ class Facebook { * * For nitty-gritty details of when each of these is used, check out * http://wiki.developers.facebook.com/index.php/Verifying_The_Signature - * - * @param bool resolve_auth_token convert an auth token into a session */ - public function validate_fb_params($resolve_auth_token=true) { + public function validate_fb_params() { $this->fb_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_sig'); // note that with preload FQL, it's possible to receive POST params in // addition to GET, so use a different prefix to differentiate them if (!$this->fb_params) { $fb_params = $this->get_valid_fb_params($_GET, 48 * 3600, 'fb_sig'); - $fb_post_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_post_sig'); + $fb_post_params = $this->get_valid_fb_params($_POST, + 48 * 3600, // 48 hours + 'fb_post_sig'); $this->fb_params = array_merge($fb_params, $fb_post_params); } @@ -128,6 +130,9 @@ class Facebook { $this->fb_params['canvas_user'] : null; $this->base_domain = isset($this->fb_params['base_domain']) ? $this->fb_params['base_domain'] : null; + $this->ext_perms = isset($this->fb_params['ext_perms']) ? + explode(',', $this->fb_params['ext_perms']) + : array(); if (isset($this->fb_params['session_key'])) { $session_key = $this->fb_params['session_key']; @@ -141,13 +146,11 @@ class Facebook { $this->set_user($user, $session_key, $expires); - } - // if no Facebook parameters were found in the GET or POST variables, - // then fall back to cookies, which may have cached user information - // Cookies are also used to receive session data via the Javascript API - else if ($cookies = - $this->get_valid_fb_params($_COOKIE, null, $this->api_key)) { - + } else if ($cookies = + $this->get_valid_fb_params($_COOKIE, null, $this->api_key)) { + // if no Facebook parameters were found in the GET or POST variables, + // then fall back to cookies, which may have cached user information + // Cookies are also used to receive session data via the Javascript API $base_domain_cookie = 'base_domain_' . $this->api_key; if (isset($_COOKIE[$base_domain_cookie])) { $this->base_domain = $_COOKIE[$base_domain_cookie]; @@ -160,25 +163,6 @@ class Facebook { $cookies['session_key'], $expires); } - // finally, if we received no parameters, but the 'auth_token' GET var - // is present, then we are in the middle of auth handshake, - // so go ahead and create the session - else if ($resolve_auth_token && isset($_GET['auth_token']) && - $session = $this->do_get_session($_GET['auth_token'])) { - if ($this->generate_session_secret && - !empty($session['secret'])) { - $session_secret = $session['secret']; - } - - if (isset($session['base_domain'])) { - $this->base_domain = $session['base_domain']; - } - - $this->set_user($session['uid'], - $session['session_key'], - $session['expires'], - isset($session_secret) ? $session_secret : null); - } return !empty($this->fb_params); } @@ -309,11 +293,28 @@ class Facebook { // require_add and require_install have been removed. // see http://developer.facebook.com/news.php?blog=1&story=116 for more details - public function require_login() { - if ($user = $this->get_loggedin_user()) { + public function require_login($required_permissions = '') { + $user = $this->get_loggedin_user(); + $has_permissions = true; + + if ($required_permissions) { + $this->require_frame(); + $permissions = array_map('trim', explode(',', $required_permissions)); + foreach ($permissions as $permission) { + if (!in_array($permission, $this->ext_perms)) { + $has_permissions = false; + break; + } + } + } + + if ($user && $has_permissions) { return $user; } - $this->redirect($this->get_login_url(self::current_url(), $this->in_frame())); + + $this->redirect( + $this->get_login_url(self::current_url(), $this->in_frame(), + $required_permissions)); } public function require_frame() { @@ -342,10 +343,11 @@ class Facebook { return $page . '?' . http_build_query($params); } - public function get_login_url($next, $canvas) { + public function get_login_url($next, $canvas, $req_perms = '') { $page = self::get_facebook_url().'/login.php'; - $params = array('api_key' => $this->api_key, - 'v' => '1.0'); + $params = array('api_key' => $this->api_key, + 'v' => '1.0', + 'req_perms' => $req_perms); if ($next) { $params['next'] = $next; diff --git a/plugins/Facebook/facebook/facebookapi_php5_restlib.php b/plugins/Facebook/facebook/facebookapi_php5_restlib.php index fa1088cd0..e249a326b 100755 --- a/plugins/Facebook/facebook/facebookapi_php5_restlib.php +++ b/plugins/Facebook/facebook/facebookapi_php5_restlib.php @@ -569,7 +569,7 @@ function toggleDisplay(id, type) { return $this->call_method('facebook.events.invite', array('eid' => $eid, 'uids' => $uids, - 'personal_message', $personal_message)); + 'personal_message' => $personal_message)); } /** @@ -1350,53 +1350,6 @@ function toggleDisplay(id, type) { ); } - /** - * Dashboard API - */ - - /** - * Set the news for the specified user. - * - * @param int $uid The user for whom you are setting news for - * @param string $news Text of news to display - * - * @return bool Success - */ - public function dashboard_setNews($uid, $news) { - return $this->call_method('facebook.dashboard.setNews', - array('uid' => $uid, - 'news' => $news) - ); - } - - /** - * Get the current news of the specified user. - * - * @param int $uid The user to get the news of - * - * @return string The text of the current news for the user - */ - public function dashboard_getNews($uid) { - return json_decode( - $this->call_method('facebook.dashboard.getNews', - array('uid' => $uid) - ), true); - } - - /** - * Set the news for the specified user. - * - * @param int $uid The user you are clearing the news of - * - * @return bool Success - */ - public function dashboard_clearNews($uid) { - return $this->call_method('facebook.dashboard.clearNews', - array('uid' => $uid) - ); - } - - /** * Creates a note with the specified title and content. @@ -2005,7 +1958,7 @@ function toggleDisplay(id, type) { * @return array A list of strings describing any compile errors for the * submitted FBML */ - function profile_setFBML($markup, + public function profile_setFBML($markup, $uid=null, $profile='', $profile_action='', @@ -3267,9 +3220,8 @@ function toggleDisplay(id, type) { } else { $get['v'] = '1.0'; } - if (isset($this->use_ssl_resources) && - $this->use_ssl_resources) { - $post['return_ssl_resources'] = true; + if (isset($this->use_ssl_resources)) { + $post['return_ssl_resources'] = (bool) $this->use_ssl_resources; } return array($get, $post); } -- cgit v1.2.3-54-g00ecf From 777ca74500025c616ae689f9a92b3233cf8466f7 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 24 May 2010 21:25:21 +0000 Subject: Upgrade Facebook posting: - Use FQL to check for publish stream permission instead of old REST API - Better error handling, especially for error code 100 - More logging / better log messages --- plugins/Facebook/facebookutil.php | 302 ++++++++++++++++++++++++++++++-------- 1 file changed, 238 insertions(+), 64 deletions(-) diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index 045891649..e52a3deae 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -81,114 +81,288 @@ function isFacebookBound($notice, $flink) { function facebookBroadcastNotice($notice) { $facebook = getFacebook(); - $flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE); + $flink = Foreign_link::getByUserID( + $notice->profile_id, + FACEBOOK_SERVICE + ); if (isFacebookBound($notice, $flink)) { // Okay, we're good to go, update the FB status - $status = null; $fbuid = $flink->foreign_id; $user = $flink->getUser(); - $attachments = $notice->attachments(); try { - // Get the status 'verb' (prefix) the user has set + // Check permissions - // XXX: Does this call count against our per user FB request limit? - // If so we should consider storing verb elsewhere or not storing + common_debug( + 'FacebookPlugin - checking for publish_stream permission for user ' + . "$user->nickname ($user->id), Facebook UID: $fbuid" + ); - $prefix = trim($facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, - $fbuid)); + // NOTE: $facebook->api_client->users_hasAppPermission('publish_stream', $fbuid) + // has been returning bogus results, so we're using FQL to check for + // publish_stream permission now - $status = "$prefix $notice->content"; + $fql = "SELECT publish_stream FROM permissions WHERE uid = $fbuid"; + $result = $facebook->api_client->fql_query($fql); - common_debug("FacebookPlugin - checking for publish_stream permission for user $user->id"); + $canPublish = 0; - $can_publish = $facebook->api_client->users_hasAppPermission('publish_stream', - $fbuid); + if (!empty($result)) { + $canPublish = $result[0]['publish_stream']; + } - common_debug("FacebookPlugin - checking for status_update permission for user $user->id"); + if ($canPublish == 1) { + common_debug( + "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " + . 'has publish_stream permission.' + ); + } else { + common_debug( + "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " + . 'does NOT have publish_stream permission. Facebook ' + . 'returned: ' . var_export($result, true) + ); + } - $can_update = $facebook->api_client->users_hasAppPermission('status_update', - $fbuid); - if (!empty($attachments) && $can_publish == 1) { - $fbattachment = format_attachments($attachments); - $facebook->api_client->stream_publish($status, $fbattachment, - null, null, $fbuid); - common_log(LOG_INFO, - "FacebookPlugin - Posted notice $notice->id w/attachment " . - "to Facebook user's stream (fbuid = $fbuid)."); - } elseif ($can_update == 1 || $can_publish == 1) { - $facebook->api_client->users_setStatus($status, $fbuid, false, true); - common_log(LOG_INFO, - "FacebookPlugin - Posted notice $notice->id to Facebook " . - "as a status update (fbuid = $fbuid)."); + common_debug( + 'FacebookPlugin - checking for status_update permission for user ' + . "$user->nickname ($user->id), Facebook UID: $fbuid. " + ); + + $canUpdate = $facebook->api_client->users_hasAppPermission( + 'status_update', + $fbuid + ); + + if ($canUpdate == 1) { + common_debug( + "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " + . 'has status_update permission.' + ); + } else { + common_debug( + "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " + .'does NOT have status_update permission. Facebook ' + . 'returned: ' . var_export($can_publish, true) + ); + } + + // Post to Facebook + + if ($notice->hasAttachments() && $canPublish == 1) { + publishStream($notice, $user, $fbuid); + } elseif ($canUpdate == 1 || $canPublish == 1) { + statusUpdate($notice, $user, $fbuid); } else { $msg = "FacebookPlugin - Not sending notice $notice->id to Facebook " . - "because user $user->nickname hasn't given the " . + "because user $user->nickname has not given the " . 'Facebook app \'status_update\' or \'publish_stream\' permission.'; common_log(LOG_WARNING, $msg); } // Finally, attempt to update the user's profile box - if ($can_publish == 1 || $can_update == 1) { - updateProfileBox($facebook, $flink, $notice); + if ($canPublish == 1 || $canUpdate == 1) { + updateProfileBox($facebook, $flink, $notice, $user); } } catch (FacebookRestClientException $e) { + return handleFacebookError($e, $notice, $flink); + } + } - $code = $e->getCode(); + return true; +} + +function handleFacebookError($e, $notice, $flink) +{ + $fbuid = $flink->foreign_id; + $user = $flink->getUser(); + $code = $e->getCode(); + $errmsg = $e->getMessage(); + + // XXX: Check for any others? + switch($code) { + case 100: // Invalid parameter + $msg = "FacebookPlugin - Facebook claims notice %d was posted with an invalid parameter (error code 100):" + . "\"%s\" (Notice details: nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). " + . "Removing notice from the Facebook queue for safety."; + common_log( + LOG_ERROR, sprintf( + $msg, + $notice->id, + $errmsg, + $user->nickname, + $user->id, + $fbuid, + $notice->content + ) + ); + return true; + break; + case 200: // Permissions error + case 250: // Updating status requires the extended permission status_update + remove_facebook_app($flink); + return true; // dequeue + break; + case 341: // Feed action request limit reached + $msg = "FacebookPlugin - User %s (User ID=%d, Facebook ID=%d) has exceeded " + . "his/her limit for posting notices to Facebook today. Dequeuing " + . "notice %d."; + common_log( + LOG_INFO, sprintf( + $msg, + $user->nickname, + $user->id, + $fbuid, + $notice->id + ) + ); + // @fixme: We want to rety at a later time when the throttling has expired + // instead of just giving up. + return true; + break; + default: + $msg = "FacebookPlugin - Facebook returned an error we don't know how to deal with while trying to " + . "post notice %d. Error code: %d, error message: \"%s\". (Notice details: " + . "nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). Re-queueing " + . "notice, and will try to send again later."; + common_log( + LOG_ERROR, sprintf( + $msg, + $notice->id, + $code, + $errmsg, + $user->nickname, + $user->id, + $fbuid, + $notice->content + ) + ); + // Re-queue and try again later + return false; + break; + } +} - $msg = "FacebookPlugin - Facebook returned error code $code: " . - $e->getMessage() . ' - ' . - "Unable to update Facebook status (notice $notice->id) " . - "for $user->nickname (user id: $user->id)!"; +function statusUpdate($notice, $user, $fbuid) +{ + common_debug( + "FacebookPlugin - Attempting to post notice $notice->id " + . "as a status update for $user->nickname ($user->id), " + . "Facebook UID: $fbuid" + ); - common_log(LOG_WARNING, $msg); + $text = formatNotice($notice, $user, $fbuid); - if ($code == 100 || $code == 200 || $code == 250) { + $facebook = getFacebook(); + $result = $facebook->api_client->users_setStatus( + $text, + $fbuid, + false, + true + ); + + common_debug('Facebook returned: ' . var_export($result, true)); + + common_log( + LOG_INFO, + "FacebookPlugin - Posted notice $notice->id as a status " + . "update for $user->nickname ($user->id), " + . "Facebook UID: $fbuid" + ); +} - // 100 The account is 'inactive' (probably - this is not well documented) - // 200 The application does not have permission to operate on the passed in uid parameter. - // 250 Updating status requires the extended permission status_update or publish_stream. - // see: http://wiki.developers.facebook.com/index.php/Users.setStatus#Example_Return_XML +function publishStream($notice, $user, $fbuid) +{ + common_debug( + "FacebookPlugin - Attempting to post notice $notice->id " + . "as stream item with attachment for $user->nickname ($user->id), " + . "Facebook UID: $fbuid" + ); - remove_facebook_app($flink); + $text = formatNotice($notice, $user, $fbuid); + $fbattachment = format_attachments($notice->attachments()); - } else if ($code == 341) { - // 341 Feed action request limit reached - Unable to update Facebook status - // Reposting immediately probably won't work, so drop the message for now. :( + $facebook = getFacebook(); + $facebook->api_client->stream_publish( + $text, + $fbattachment, + null, + null, + $fbuid + ); + + common_debug('Facebook returned: ' . var_export($result, true)); + + common_log( + LOG_INFO, + "FacebookPlugin - Posted notice $notice->id as a stream " + . "item with attachment for $user->nickname ($user->id), " + . "Facebook UID: $fbuid" + ); +} - common_log(LOG_ERR, "Facebook rate limit hit: dropping notice $notice->id"); - return true; - } else { - // Try sending again later. - // - // @fixme at the moment, returning false here could lead to an infinite loop - // if the error condition isn't actually transitory. - // - // Temporarily throwing an exception to kill the process so it'll hit our - // retry limits. - throw new Exception("Facebook error $code on notice $notice->id"); +function formatNotice($notice, $user, $fbuid) +{ + // Get the status 'verb' the user has set, if any - return false; - } + common_debug( + "FacebookPlugin - Looking to see if $user->nickname ($user->id), " + . "Facebook UID: $fbuid has set a verb for Facebook posting..." + ); - } + $facebook = getFacebook(); + $verb = trim( + $facebook->api_client->data_getUserPreference( + FACEBOOK_NOTICE_PREFIX, + $fbuid + ) + ); + + common_debug("Facebook returned " . var_export($verb, true)); + + $text = null; + + if (!empty($verb)) { + common_debug("FacebookPlugin - found a verb: $verb"); + $text = trim($verb) . ' ' . $notice->content; + } else { + common_debug("FacebookPlugin - no verb found."); + $text = $notice->content; } - return true; - + return $text; } -function updateProfileBox($facebook, $flink, $notice) { - $fbaction = new FacebookAction($output = 'php://output', - $indent = null, $facebook, $flink); +function updateProfileBox($facebook, $flink, $notice, $user) { + + $facebook = getFacebook(); + $fbaction = new FacebookAction( + $output = 'php://output', + $indent = null, + $facebook, + $flink + ); + + common_debug( + 'FacebookPlugin - Attempting to update profile box with ' + . "content from notice $notice->id for $user->nickname ($user->id)" + . "Facebook UID: $fbuid" + ); + $fbaction->updateProfileBox($notice); + + common_debug( + 'FacebookPlugin - finished updating profile box for ' + . "$user->nickname ($user->id) Facebook UID: $fbuid" + ); + } function format_attachments($attachments) -- cgit v1.2.3-54-g00ecf From 1f3a16bbfb41b366bea05f5ba05bb41f44108ab8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 24 May 2010 22:41:34 +0000 Subject: Clear up warnings I introduced by refactoring Facebook posting --- plugins/Facebook/facebookutil.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index e52a3deae..d573c34ac 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -147,7 +147,7 @@ function facebookBroadcastNotice($notice) common_debug( "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " .'does NOT have status_update permission. Facebook ' - . 'returned: ' . var_export($can_publish, true) + . 'returned: ' . var_export($canPublish, true) ); } @@ -297,8 +297,6 @@ function publishStream($notice, $user, $fbuid) $fbuid ); - common_debug('Facebook returned: ' . var_export($result, true)); - common_log( LOG_INFO, "FacebookPlugin - Posted notice $notice->id as a stream " @@ -307,7 +305,6 @@ function publishStream($notice, $user, $fbuid) ); } - function formatNotice($notice, $user, $fbuid) { // Get the status 'verb' the user has set, if any @@ -350,6 +347,8 @@ function updateProfileBox($facebook, $flink, $notice, $user) { $flink ); + $fbuid = $flink->foreign_id; + common_debug( 'FacebookPlugin - Attempting to update profile box with ' . "content from notice $notice->id for $user->nickname ($user->id)" -- cgit v1.2.3-54-g00ecf From 9cde924bb3f928d9df0519a9a6b995633eb45789 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 24 May 2010 23:27:53 +0000 Subject: Accidentally used the wrong log level (LOG ERROR instead of LOG_ERR) --- plugins/Facebook/facebookutil.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index d573c34ac..0f24f5441 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -192,7 +192,7 @@ function handleFacebookError($e, $notice, $flink) . "\"%s\" (Notice details: nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). " . "Removing notice from the Facebook queue for safety."; common_log( - LOG_ERROR, sprintf( + LOG_ERR, sprintf( $msg, $notice->id, $errmsg, @@ -232,7 +232,7 @@ function handleFacebookError($e, $notice, $flink) . "nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). Re-queueing " . "notice, and will try to send again later."; common_log( - LOG_ERROR, sprintf( + LOG_ERR, sprintf( $msg, $notice->id, $code, @@ -351,7 +351,7 @@ function updateProfileBox($facebook, $flink, $notice, $user) { common_debug( 'FacebookPlugin - Attempting to update profile box with ' - . "content from notice $notice->id for $user->nickname ($user->id)" + . "content from notice $notice->id for $user->nickname ($user->id), " . "Facebook UID: $fbuid" ); -- cgit v1.2.3-54-g00ecf From 09dab2ce5ae819c73d7984822d418c43f1fba223 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 25 May 2010 15:40:38 +0000 Subject: Dequeue notice when we hit any Facebook error. --- plugins/Facebook/facebookutil.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index 0f24f5441..c7b0f02c3 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -229,8 +229,8 @@ function handleFacebookError($e, $notice, $flink) default: $msg = "FacebookPlugin - Facebook returned an error we don't know how to deal with while trying to " . "post notice %d. Error code: %d, error message: \"%s\". (Notice details: " - . "nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). Re-queueing " - . "notice, and will try to send again later."; + . "nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). Removing notice " + . "from the Facebook queue for safety."; common_log( LOG_ERR, sprintf( $msg, @@ -243,8 +243,7 @@ function handleFacebookError($e, $notice, $flink) $notice->content ) ); - // Re-queue and try again later - return false; + return true; // dequeue break; } } -- cgit v1.2.3-54-g00ecf From f98609204fb9b5966b9e4c9e4bf8bf605656c31c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 25 May 2010 11:36:42 -0700 Subject: Backing out locale switch change to see if this affects our mystery memory leak. Revert "Locale switch cleanup: use common_switch_locale() which is safer for updating gettext state. Also moved a few calls to reduce chance of hitting an exception before switching back." This reverts commit 74a89b1fc37067d91d31bd66922053361eb4e616. --- lib/mail.php | 20 ++++++++++---------- lib/util.php | 17 ----------------- plugins/Facebook/facebookutil.php | 6 +++--- plugins/TwitterBridge/twitter.php | 6 +++--- 4 files changed, 16 insertions(+), 33 deletions(-) diff --git a/lib/mail.php b/lib/mail.php index ab5742e33..f45b2d333 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -224,6 +224,9 @@ function mail_subscribe_notify_profile($listenee, $other) if ($other->hasRight(Right::EMAILONSUBSCRIBE) && $listenee->email && $listenee->emailnotifysub) { + // use the recipient's localization + common_init_locale($listenee->language); + $profile = $listenee->getProfile(); $name = $profile->getBestName(); @@ -233,9 +236,6 @@ function mail_subscribe_notify_profile($listenee, $other) $recipients = $listenee->email; - // use the recipient's localization - common_switch_locale($listenee->language); - $headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname); $headers['From'] = mail_notify_from(); $headers['To'] = $name . ' <' . $listenee->email . '>'; @@ -277,7 +277,7 @@ function mail_subscribe_notify_profile($listenee, $other) common_local_url('emailsettings')); // reset localization - common_switch_locale(); + common_init_locale(); mail_send($recipients, $headers, $body); } } @@ -479,7 +479,7 @@ function mail_confirm_sms($code, $nickname, $address) function mail_notify_nudge($from, $to) { - common_switch_locale($to->language); + common_init_locale($to->language); // TRANS: Subject for 'nudge' notification email $subject = sprintf(_('You\'ve been nudged by %s'), $from->nickname); @@ -497,7 +497,7 @@ function mail_notify_nudge($from, $to) $from->nickname, common_local_url('all', array('nickname' => $to->nickname)), common_config('site', 'name')); - common_switch_locale(); + common_init_locale(); $headers = _mail_prepare_headers('nudge', $to->nickname, $from->nickname); @@ -531,7 +531,7 @@ function mail_notify_message($message, $from=null, $to=null) return true; } - common_switch_locale($to->language); + common_init_locale($to->language); // TRANS: Subject for direct-message notification email $subject = sprintf(_('New private message from %s'), $from->nickname); @@ -555,7 +555,7 @@ function mail_notify_message($message, $from=null, $to=null) $headers = _mail_prepare_headers('message', $to->nickname, $from->nickname); - common_switch_locale(); + common_init_locale(); return mail_to_user($to, $subject, $body, $headers); } @@ -583,7 +583,7 @@ function mail_notify_fave($other, $user, $notice) $bestname = $profile->getBestName(); - common_switch_locale($other->language); + common_init_locale($other->language); // TRANS: Subject for favorite notification email $subject = sprintf(_('%s (@%s) added your notice as a favorite'), $bestname, $user->nickname); @@ -611,7 +611,7 @@ function mail_notify_fave($other, $user, $notice) $headers = _mail_prepare_headers('fave', $other->nickname, $user->nickname); - common_switch_locale(); + common_init_locale(); mail_to_user($other, $subject, $body, $headers); } diff --git a/lib/util.php b/lib/util.php index 59d5132ec..eed61d029 100644 --- a/lib/util.php +++ b/lib/util.php @@ -34,14 +34,6 @@ function common_user_error($msg, $code=400) $err->showPage(); } -/** - * This should only be used at setup; processes switching languages - * to send text to other users should use common_switch_locale(). - * - * @param string $language Locale language code (optional; empty uses - * current user's preference or site default) - * @return mixed success - */ function common_init_locale($language=null) { if(!$language) { @@ -58,15 +50,6 @@ function common_init_locale($language=null) return $ok; } -/** - * Initialize locale and charset settings and gettext with our message catalog, - * using the current user's language preference or the site default. - * - * This should generally only be run at framework initialization; code switching - * languages at runtime should call common_switch_language(). - * - * @access private - */ function common_init_language() { mb_internal_encoding('UTF-8'); diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index c7b0f02c3..9c35276b7 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -461,12 +461,12 @@ function remove_facebook_app($flink) function mail_facebook_app_removed($user) { + common_init_locale($user->language); + $profile = $user->getProfile(); $site_name = common_config('site', 'name'); - common_switch_locale($user->language); - $subject = sprintf( _m('Your %1$s Facebook application access has been disabled.', $site_name)); @@ -480,7 +480,7 @@ function mail_facebook_app_removed($user) "re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"), $user->nickname, $site_name); - common_switch_locale(); + common_init_locale(); return mail_to_user($user, $subject, $body); } diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 896eee2da..21adc7a90 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -335,9 +335,9 @@ function remove_twitter_link($flink) function mail_twitter_bridge_removed($user) { - $profile = $user->getProfile(); + common_init_locale($user->language); - common_switch_locale($user->language); + $profile = $user->getProfile(); $subject = sprintf(_m('Your Twitter bridge has been disabled.')); @@ -354,7 +354,7 @@ function mail_twitter_bridge_removed($user) common_local_url('twittersettings'), common_config('site', 'name')); - common_switch_locale(); + common_init_locale(); return mail_to_user($user, $subject, $body); } -- cgit v1.2.3-54-g00ecf From 3d4ce6f10b94d487e8eff89f689fba22327634f0 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 25 May 2010 12:31:16 -0700 Subject: Revert "Backing out locale switch change to see if this affects our mystery memory leak." This reverts commit f98609204fb9b5966b9e4c9e4bf8bf605656c31c. --- lib/mail.php | 20 ++++++++++---------- lib/util.php | 17 +++++++++++++++++ plugins/Facebook/facebookutil.php | 6 +++--- plugins/TwitterBridge/twitter.php | 6 +++--- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/lib/mail.php b/lib/mail.php index f45b2d333..ab5742e33 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -224,9 +224,6 @@ function mail_subscribe_notify_profile($listenee, $other) if ($other->hasRight(Right::EMAILONSUBSCRIBE) && $listenee->email && $listenee->emailnotifysub) { - // use the recipient's localization - common_init_locale($listenee->language); - $profile = $listenee->getProfile(); $name = $profile->getBestName(); @@ -236,6 +233,9 @@ function mail_subscribe_notify_profile($listenee, $other) $recipients = $listenee->email; + // use the recipient's localization + common_switch_locale($listenee->language); + $headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname); $headers['From'] = mail_notify_from(); $headers['To'] = $name . ' <' . $listenee->email . '>'; @@ -277,7 +277,7 @@ function mail_subscribe_notify_profile($listenee, $other) common_local_url('emailsettings')); // reset localization - common_init_locale(); + common_switch_locale(); mail_send($recipients, $headers, $body); } } @@ -479,7 +479,7 @@ function mail_confirm_sms($code, $nickname, $address) function mail_notify_nudge($from, $to) { - common_init_locale($to->language); + common_switch_locale($to->language); // TRANS: Subject for 'nudge' notification email $subject = sprintf(_('You\'ve been nudged by %s'), $from->nickname); @@ -497,7 +497,7 @@ function mail_notify_nudge($from, $to) $from->nickname, common_local_url('all', array('nickname' => $to->nickname)), common_config('site', 'name')); - common_init_locale(); + common_switch_locale(); $headers = _mail_prepare_headers('nudge', $to->nickname, $from->nickname); @@ -531,7 +531,7 @@ function mail_notify_message($message, $from=null, $to=null) return true; } - common_init_locale($to->language); + common_switch_locale($to->language); // TRANS: Subject for direct-message notification email $subject = sprintf(_('New private message from %s'), $from->nickname); @@ -555,7 +555,7 @@ function mail_notify_message($message, $from=null, $to=null) $headers = _mail_prepare_headers('message', $to->nickname, $from->nickname); - common_init_locale(); + common_switch_locale(); return mail_to_user($to, $subject, $body, $headers); } @@ -583,7 +583,7 @@ function mail_notify_fave($other, $user, $notice) $bestname = $profile->getBestName(); - common_init_locale($other->language); + common_switch_locale($other->language); // TRANS: Subject for favorite notification email $subject = sprintf(_('%s (@%s) added your notice as a favorite'), $bestname, $user->nickname); @@ -611,7 +611,7 @@ function mail_notify_fave($other, $user, $notice) $headers = _mail_prepare_headers('fave', $other->nickname, $user->nickname); - common_init_locale(); + common_switch_locale(); mail_to_user($other, $subject, $body, $headers); } diff --git a/lib/util.php b/lib/util.php index eed61d029..59d5132ec 100644 --- a/lib/util.php +++ b/lib/util.php @@ -34,6 +34,14 @@ function common_user_error($msg, $code=400) $err->showPage(); } +/** + * This should only be used at setup; processes switching languages + * to send text to other users should use common_switch_locale(). + * + * @param string $language Locale language code (optional; empty uses + * current user's preference or site default) + * @return mixed success + */ function common_init_locale($language=null) { if(!$language) { @@ -50,6 +58,15 @@ function common_init_locale($language=null) return $ok; } +/** + * Initialize locale and charset settings and gettext with our message catalog, + * using the current user's language preference or the site default. + * + * This should generally only be run at framework initialization; code switching + * languages at runtime should call common_switch_language(). + * + * @access private + */ function common_init_language() { mb_internal_encoding('UTF-8'); diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index 9c35276b7..c7b0f02c3 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -461,12 +461,12 @@ function remove_facebook_app($flink) function mail_facebook_app_removed($user) { - common_init_locale($user->language); - $profile = $user->getProfile(); $site_name = common_config('site', 'name'); + common_switch_locale($user->language); + $subject = sprintf( _m('Your %1$s Facebook application access has been disabled.', $site_name)); @@ -480,7 +480,7 @@ function mail_facebook_app_removed($user) "re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"), $user->nickname, $site_name); - common_init_locale(); + common_switch_locale(); return mail_to_user($user, $subject, $body); } diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 21adc7a90..896eee2da 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -335,10 +335,10 @@ function remove_twitter_link($flink) function mail_twitter_bridge_removed($user) { - common_init_locale($user->language); - $profile = $user->getProfile(); + common_switch_locale($user->language); + $subject = sprintf(_m('Your Twitter bridge has been disabled.')); $site_name = common_config('site', 'name'); @@ -354,7 +354,7 @@ function mail_twitter_bridge_removed($user) common_local_url('twittersettings'), common_config('site', 'name')); - common_init_locale(); + common_switch_locale(); return mail_to_user($user, $subject, $body); } -- cgit v1.2.3-54-g00ecf From 95159112b2331ee832a4cf1e711cb8f1f0193c44 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 25 May 2010 13:09:21 -0700 Subject: Hotpatch for infinite redirection-following loop seen processing URLs to http://clojure.org/ -- if we end up with an unstable redirect target (final item in a redirect chain ends up redirecting us somewhere else when we visit it again), just save the last version we saw instead of trying to start over. Pretty much everything in File and File_redirection initial processing needs to be rewritten to be non-awful; this code is very hard to follow and very easy to make huge bugs. A fair amount of the complication is probably obsoleted by the redirection following being built into HTTPClient now. --- classes/File.php | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/classes/File.php b/classes/File.php index 33273bbdc..8297e5091 100644 --- a/classes/File.php +++ b/classes/File.php @@ -116,7 +116,11 @@ class File extends Memcached_DataObject return false; } - function processNew($given_url, $notice_id=null) { + /** + * @fixme refactor this mess, it's gotten pretty scary. + * @param bool $followRedirects + */ + function processNew($given_url, $notice_id=null, $followRedirects=true) { if (empty($given_url)) return -1; // error, no url to process $given_url = File_redirection::_canonUrl($given_url); if (empty($given_url)) return -1; // error, no url to process @@ -124,6 +128,10 @@ class File extends Memcached_DataObject if (empty($file)) { $file_redir = File_redirection::staticGet('url', $given_url); if (empty($file_redir)) { + // @fixme for new URLs this also looks up non-redirect data + // such as target content type, size, etc, which we need + // for File::saveNew(); so we call it even if not following + // new redirects. $redir_data = File_redirection::where($given_url); if (is_array($redir_data)) { $redir_url = $redir_data['url']; @@ -134,11 +142,19 @@ class File extends Memcached_DataObject throw new ServerException("Can't process url '$given_url'"); } // TODO: max field length - if ($redir_url === $given_url || strlen($redir_url) > 255) { + if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) { $x = File::saveNew($redir_data, $given_url); $file_id = $x->id; } else { - $x = File::processNew($redir_url, $notice_id); + // This seems kind of messed up... for now skipping this part + // if we're already under a redirect, so we don't go into + // horrible infinite loops if we've been given an unstable + // redirect (where the final destination of the first request + // doesn't match what we get when we ask for it again). + // + // Seen in the wild with clojure.org, which redirects through + // wikispaces for auth and appends session data in the URL params. + $x = File::processNew($redir_url, $notice_id, /*followRedirects*/false); $file_id = $x->id; File_redirection::saveNew($redir_data, $file_id, $given_url); } -- cgit v1.2.3-54-g00ecf From d9a89d174ad1cb28669a8f3c76be23f27c182d58 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 25 May 2010 21:08:25 +0000 Subject: Small update to the README: Facebook has changed the name of one of its application settings fields. --- plugins/Facebook/README | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/Facebook/README b/plugins/Facebook/README index 14c1d3241..532f1d82e 100644 --- a/plugins/Facebook/README +++ b/plugins/Facebook/README @@ -38,11 +38,11 @@ editor or write them down. In Facebook's application editor, specify the following URLs for your app: -- Canvas Callback URL : http://example.net/mublog/facebook/app/ -- Post-Remove Callback URL: http://example.net/mublog/facebook/app/remove -- Post-Add Redirect URL : http://apps.facebook.com/yourapp/ -- Canvas Page URL : http://apps.facebook.com/yourapp/ -- Connect URL : http://example.net/mublog/ +- Canvas Callback URL : http://example.net/mublog/facebook/app/ +- Post-Remove Callback URL : http://example.net/mublog/facebook/app/remove +- Post-Authorize Redirect URL : http://apps.facebook.com/yourapp/ +- Canvas Page URL : http://apps.facebook.com/yourapp/ +- Connect URL : http://example.net/mublog/ *** ATTENTION *** These URLs have changed slightly since StatusNet version 0.8.1, -- cgit v1.2.3-54-g00ecf From 9193c110f14e09523791683e7799a45163b881c2 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 20 May 2010 12:21:29 -0700 Subject: WikiHowProfile plugin; pulls avatar from WikiHow profile pages when registering or adding account with OpenID. (Full name, location, homepage, and bio are also on the profile page but not marked up in a way they can be easily retrieved yet.) OpenID plugin: Added events at OpenID account creation and update time to allow additional customizations for particular sites. --- plugins/OpenID/finishaddopenid.php | 11 +- plugins/OpenID/finishopenidlogin.php | 10 +- plugins/OpenID/openid.php | 11 +- plugins/WikiHowProfile/README | 6 + plugins/WikiHowProfile/WikiHowProfilePlugin.php | 196 ++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 9 deletions(-) create mode 100644 plugins/WikiHowProfile/README create mode 100644 plugins/WikiHowProfile/WikiHowProfilePlugin.php diff --git a/plugins/OpenID/finishaddopenid.php b/plugins/OpenID/finishaddopenid.php index 991e6584e..18e150a83 100644 --- a/plugins/OpenID/finishaddopenid.php +++ b/plugins/OpenID/finishaddopenid.php @@ -126,12 +126,15 @@ class FinishaddopenidAction extends Action $this->message(_m('Error connecting user.')); return; } - if ($sreg) { - if (!oid_update_user($cur, $sreg)) { - $this->message(_m('Error updating profile')); - return; + if (Event::handle('StartOpenIDUpdateUser', array($cur, $canonical, &$sreg))) { + if ($sreg) { + if (!oid_update_user($cur, $sreg)) { + $this->message(_m('Error updating profile')); + return; + } } } + Event::handle('EndOpenIDUpdateUser', array($cur, $canonical, $sreg)); // success! diff --git a/plugins/OpenID/finishopenidlogin.php b/plugins/OpenID/finishopenidlogin.php index 32b092a0b..60d46d4ce 100644 --- a/plugins/OpenID/finishopenidlogin.php +++ b/plugins/OpenID/finishopenidlogin.php @@ -280,6 +280,8 @@ class FinishopenidloginAction extends Action return; } + Event::handle('StartOpenIDCreateNewUser', array($canonical, &$sreg)); + $location = ''; if (!empty($sreg['country'])) { if ($sreg['postcode']) { @@ -319,6 +321,8 @@ class FinishopenidloginAction extends Action $result = oid_link_user($user->id, $canonical, $display); + Event::handle('EndOpenIDCreateNewUser', array($user, $canonical, $sreg)); + oid_set_last($display); common_set_user($user); common_real_login(true); @@ -358,7 +362,11 @@ class FinishopenidloginAction extends Action return; } - oid_update_user($user, $sreg); + if (Event::handle('StartOpenIDUpdateUser', array($user, $canonical, &$sreg))) { + oid_update_user($user, $sreg); + } + Event::handle('EndOpenIDUpdateUser', array($user, $canonical, $sreg)); + oid_set_last($display); common_set_user($user); common_real_login(true); diff --git a/plugins/OpenID/openid.php b/plugins/OpenID/openid.php index 4ec336e1c..cdeedbf4d 100644 --- a/plugins/OpenID/openid.php +++ b/plugins/OpenID/openid.php @@ -212,11 +212,14 @@ function _oid_print_instructions() 'OpenID provider.')); } -# update a user from sreg parameters - -function oid_update_user(&$user, &$sreg) +/** + * Update a user from sreg parameters + * @param User $user + * @param array $sreg fields from OpenID sreg response + * @access private + */ +function oid_update_user($user, $sreg) { - $profile = $user->getProfile(); $orig_profile = clone($profile); diff --git a/plugins/WikiHowProfile/README b/plugins/WikiHowProfile/README new file mode 100644 index 000000000..ee6096c9f --- /dev/null +++ b/plugins/WikiHowProfile/README @@ -0,0 +1,6 @@ +This is an additional plugin which piggybacks on OpenID authentication to pull +profile information from WikiHow user pages when creating or updating accounts. + +WikiHow runs a customized MediaWiki setup, with locally-built extensions to add +profile features such as an avatar. As this additional info isn't yet exposed +through OpenID, we need to pull it separately. diff --git a/plugins/WikiHowProfile/WikiHowProfilePlugin.php b/plugins/WikiHowProfile/WikiHowProfilePlugin.php new file mode 100644 index 000000000..b72bd55d6 --- /dev/null +++ b/plugins/WikiHowProfile/WikiHowProfilePlugin.php @@ -0,0 +1,196 @@ +. + * + * @category Plugins + * @package StatusNet + * @author Brion Vibber + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 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); +} + +/** + * Sample plugin main class + * + * Each plugin requires a main class to interact with the StatusNet system. + * + * @category Plugins + * @package WikiHowProfilePlugin + * @author Brion Vibber + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class WikiHowProfilePlugin extends Plugin +{ + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'WikiHow avatar fetcher', + 'version' => STATUSNET_VERSION, + 'author' => 'Brion Vibber', + 'homepage' => 'http://status.net/wiki/Plugin:Sample', + 'rawdescription' => + _m('Fetches avatar and other profile info for WikiHow users when setting up an account via OpenID.')); + return true; + } + + /** + * Hook for OpenID user creation; we'll pull the avatar. + * + * @param User $user + * @param string $canonical OpenID provider URL + * @param array $sreg query data from provider + */ + function onEndOpenIDCreateNewUser($user, $canonical, $sreg) + { + $this->updateProfile($user, $canonical); + return true; + } + + /** + * Hook for OpenID profile updating; we'll pull the avatar. + * + * @param User $user + * @param string $canonical OpenID provider URL (wiki profile page) + * @param array $sreg query data from provider + */ + function onEndOpenIDUpdateUser($user, $canonical, $sreg) + { + $this->updateProfile($user, $canonical); + return true; + } + + /** + * @param User $user + * @param string $canonical OpenID provider URL (wiki profile page) + */ + private function updateProfile($user, $canonical) + { + $prefix = 'http://www.wikihow.com/User:'; + + if (substr($canonical, 0, strlen($prefix)) == $prefix) { + // Yes, it's a WikiHow user! + $profile = $this->fetchProfile($canonical); + + if (!empty($profile['avatar'])) { + $this->saveAvatar($user, $profile['avatar']); + } + } + } + + /** + * Given a user's WikiHow profile URL, find their avatar. + * + * @param string $profileUrl user page on the wiki + * + * @return array of data; possible members: + * 'avatar' => full URL to avatar image + * + * @throws Exception on various low-level failures + * + * @todo pull location, web site, and about sections -- they aren't currently marked up cleanly. + */ + private function fetchProfile($profileUrl) + { + $client = HTTPClient::start(); + $response = $client->get($profileUrl); + if (!$response->isOk()) { + throw new Exception("WikiHow profile page fetch failed."); + // HTTP error response already logged. + return false; + } + + // Suppress warnings during HTML parsing; non-well-formed bits will + // spew horrible warning everywhere even though it works fine. + $old = error_reporting(); + error_reporting($old & ~E_WARNING); + + $dom = new DOMDocument(); + $ok = $dom->loadHTML($response->getBody()); + + error_reporting($old); + + if (!$ok) { + throw new Exception("HTML parse failure during check for WikiHow avatar."); + return false; + } + + $data = array(); + + $avatar = $dom->getElementById('avatarULimg'); + if ($avatar) { + $src = $avatar->getAttribute('src'); + + $base = new Net_URL2($profileUrl); + $absolute = $base->resolve($src); + $avatarUrl = strval($absolute); + + common_log(LOG_DEBUG, "WikiHow avatar found for $profileUrl - $avatarUrl"); + $data['avatar'] = $avatarUrl; + } + + return $data; + } + + /** + * Actually save the avatar we found locally. + * + * @param User $user + * @param string $url to avatar URL + * @todo merge wrapper funcs for this into common place for 1.0 core + */ + private function saveAvatar($user, $url) + { + if (!common_valid_http_url($url)) { + throw new ServerException(sprintf(_m("Invalid avatar URL %s"), $url)); + } + + // @fixme this should be better encapsulated + // ripped from OStatus via oauthstore.php (for old OMB client) + $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); + if (!copy($url, $temp_filename)) { + throw new ServerException(sprintf(_m("Unable to fetch avatar from %s"), $url)); + } + + $profile = $user->getProfile(); + $id = $profile->id; + // @fixme should we be using different ids? + + $imagefile = new ImageFile($id, $temp_filename); + $filename = Avatar::filename($id, + image_type_to_extension($imagefile->type), + null, + common_timestamp()); + rename($temp_filename, Avatar::path($filename)); + $profile->setOriginal($filename); + } + +} + -- cgit v1.2.3-54-g00ecf From 80d1e86a7c54521f364600c85c9f29ff29aaa611 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 26 May 2010 00:39:44 +0000 Subject: Add repeat info to statusnet:notice_info Atom element --- classes/Notice.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index d85c8cd33..3d7d21533 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1240,7 +1240,7 @@ class Notice extends Memcached_DataObject $noticeInfoAttr = array( 'local_id' => $this->id, // local notice ID (useful to clients for ordering) - 'source' => $this->source // the client name (source attribution) + 'source' => $this->source, // the client name (source attribution) ); $ns = $this->getSource(); @@ -1251,7 +1251,11 @@ class Notice extends Memcached_DataObject } if (!empty($cur)) { - $noticeInfoAttr['favorited'] = ($cur->hasFave($this)) ? 'true' : 'false'; + $noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false"; + } + + if (!empty($this->repeat_of)) { + $noticeInfoAttr['repeat_of'] = $this->repeat_of; } $xs->element('statusnet:notice_info', $noticeInfoAttr, null); -- cgit v1.2.3-54-g00ecf From 3e9b35677746ba0a9877fd1a20ef4e3ae52bc7b5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 26 May 2010 20:31:36 +0000 Subject: Remove settting/getting a 'verb' for Facebook stream entries / status updates. Facebook has disabled the ability to store user preferences via their old REST API, causing our application to break. Also, verbs in status updates seem to be deprecated, and stream posts don't seem to have a verb. --- plugins/Facebook/facebooksettings.php | 21 ------------------- plugins/Facebook/facebookutil.php | 39 ++--------------------------------- 2 files changed, 2 insertions(+), 58 deletions(-) diff --git a/plugins/Facebook/facebooksettings.php b/plugins/Facebook/facebooksettings.php index 766d0e199..f94a346b5 100644 --- a/plugins/Facebook/facebooksettings.php +++ b/plugins/Facebook/facebooksettings.php @@ -54,22 +54,11 @@ class FacebooksettingsAction extends FacebookAction $noticesync = $this->boolean('noticesync'); $replysync = $this->boolean('replysync'); - $prefix = $this->trimmed('prefix'); $original = clone($this->flink); $this->flink->set_flags($noticesync, false, $replysync, false); $result = $this->flink->update($original); - if ($prefix == '' || $prefix == '0') { - // Facebook bug: saving empty strings to prefs now fails - // http://bugs.developers.facebook.com/show_bug.cgi?id=7110 - $trimmed = $prefix . ' '; - } else { - $trimmed = substr($prefix, 0, 128); - } - $this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX, - $trimmed); - if ($result === false) { $this->showForm(_m('There was a problem saving your sync preferences!')); } else { @@ -110,16 +99,6 @@ class FacebooksettingsAction extends FacebookAction $this->elementStart('li'); - $prefix = trim($this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX)); - - $this->input('prefix', _m('Prefix'), - ($prefix) ? $prefix : null, - _m('A string to prefix notices with.')); - - $this->elementEnd('li'); - - $this->elementStart('li'); - $this->submit('save', _m('Save')); $this->elementEnd('li'); diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php index c7b0f02c3..1290fed55 100644 --- a/plugins/Facebook/facebookutil.php +++ b/plugins/Facebook/facebookutil.php @@ -256,11 +256,9 @@ function statusUpdate($notice, $user, $fbuid) . "Facebook UID: $fbuid" ); - $text = formatNotice($notice, $user, $fbuid); - $facebook = getFacebook(); $result = $facebook->api_client->users_setStatus( - $text, + $notice->content, $fbuid, false, true @@ -284,12 +282,11 @@ function publishStream($notice, $user, $fbuid) . "Facebook UID: $fbuid" ); - $text = formatNotice($notice, $user, $fbuid); $fbattachment = format_attachments($notice->attachments()); $facebook = getFacebook(); $facebook->api_client->stream_publish( - $text, + $notice->content, $fbattachment, null, null, @@ -304,38 +301,6 @@ function publishStream($notice, $user, $fbuid) ); } -function formatNotice($notice, $user, $fbuid) -{ - // Get the status 'verb' the user has set, if any - - common_debug( - "FacebookPlugin - Looking to see if $user->nickname ($user->id), " - . "Facebook UID: $fbuid has set a verb for Facebook posting..." - ); - - $facebook = getFacebook(); - $verb = trim( - $facebook->api_client->data_getUserPreference( - FACEBOOK_NOTICE_PREFIX, - $fbuid - ) - ); - - common_debug("Facebook returned " . var_export($verb, true)); - - $text = null; - - if (!empty($verb)) { - common_debug("FacebookPlugin - found a verb: $verb"); - $text = trim($verb) . ' ' . $notice->content; - } else { - common_debug("FacebookPlugin - no verb found."); - $text = $notice->content; - } - - return $text; -} - function updateProfileBox($facebook, $flink, $notice, $user) { $facebook = getFacebook(); -- cgit v1.2.3-54-g00ecf From c5b61078e1548fba2820620e2e8f5fcbbda611a8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 27 May 2010 13:49:23 -0700 Subject: Pass auth user into Atom feed generators (needed for outputting favorited status in statusnet:notice_info tag) --- actions/apitimelinefavorites.php | 2 +- actions/apitimelinefriends.php | 2 +- actions/apitimelinegroup.php | 2 +- actions/apitimelinehome.php | 2 +- actions/apitimelinementions.php | 2 +- actions/apitimelinepublic.php | 2 +- actions/apitimelineretweetsofme.php | 2 +- actions/apitimelinetag.php | 2 +- actions/apitimelineuser.php | 2 +- lib/atomgroupnoticefeed.php | 5 +++-- lib/atomnoticefeed.php | 17 +++++++++++++++-- lib/atomusernoticefeed.php | 5 +++-- 12 files changed, 30 insertions(+), 15 deletions(-) diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php index 79632447e..a889b4918 100644 --- a/actions/apitimelinefavorites.php +++ b/actions/apitimelinefavorites.php @@ -150,7 +150,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index ac350ab1b..9c6ffcf9c 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -152,7 +152,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index 56d1de094..76fa74767 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -105,7 +105,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction function showTimeline() { // We'll pull common formatting out of this for other formats - $atom = new AtomGroupNoticeFeed($this->group); + $atom = new AtomGroupNoticeFeed($this->group, $this->auth_user); $self = $this->getSelfUri(); diff --git a/actions/apitimelinehome.php b/actions/apitimelinehome.php index 1618c9923..2a6b7bf5c 100644 --- a/actions/apitimelinehome.php +++ b/actions/apitimelinehome.php @@ -151,7 +151,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php index c3aec7c5a..dc39122e5 100644 --- a/actions/apitimelinementions.php +++ b/actions/apitimelinementions.php @@ -151,7 +151,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index 903461425..49062e603 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -130,7 +130,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelineretweetsofme.php b/actions/apitimelineretweetsofme.php index c77912fd0..ea922fc42 100644 --- a/actions/apitimelineretweetsofme.php +++ b/actions/apitimelineretweetsofme.php @@ -117,7 +117,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php index fed1437ea..c21b22702 100644 --- a/actions/apitimelinetag.php +++ b/actions/apitimelinetag.php @@ -138,7 +138,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + $atom = new AtomNoticeFeed($this->auth_user); $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 11431a82c..9ee6abaf5 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -115,7 +115,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction // We'll use the shared params from the Atom stub // for other feed types. - $atom = new AtomUserNoticeFeed($this->user); + $atom = new AtomUserNoticeFeed($this->user, $this->auth_user); $link = common_local_url( 'showstream', diff --git a/lib/atomgroupnoticefeed.php b/lib/atomgroupnoticefeed.php index 08c1c707c..7934a4f9e 100644 --- a/lib/atomgroupnoticefeed.php +++ b/lib/atomgroupnoticefeed.php @@ -50,12 +50,13 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed * Constructor * * @param Group $group the group for the feed + * @param User $cur the current authenticated user, if any * @param boolean $indent flag to turn indenting on or off * * @return void */ - function __construct($group, $indent = true) { - parent::__construct($indent); + function __construct($group, $cur = null, $indent = true) { + parent::__construct($cur, $indent); $this->group = $group; $title = sprintf(_("%s timeline"), $group->nickname); diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index 35a45118c..ef44de4b6 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -44,9 +44,22 @@ if (!defined('STATUSNET')) */ class AtomNoticeFeed extends Atom10Feed { - function __construct($indent = true) { + var $cur; + + /** + * Constructor - adds a bunch of XML namespaces we need in our + * notice-specific Atom feeds, and allows setting the current + * authenticated user (useful for API methods). + * + * @param User $cur the current authenticated user (optional) + * @param boolean $indent Whether to indent XML output + * + */ + function __construct($cur = null, $indent = true) { parent::__construct($indent); + $this->cur = $cur; + // Feeds containing notice info use these namespaces $this->addNamespace( @@ -115,7 +128,7 @@ class AtomNoticeFeed extends Atom10Feed $source = $this->showSource(); $author = $this->showAuthor(); - $cur = common_current_user(); + $cur = empty($this->cur) ? common_current_user() : $this->cur; $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); } diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index 428cc2de2..b569d9379 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -50,13 +50,14 @@ class AtomUserNoticeFeed extends AtomNoticeFeed * Constructor * * @param User $user the user for the feed + * @param User $cur the current authenticated user, if any * @param boolean $indent flag to turn indenting on or off * * @return void */ - function __construct($user, $indent = true) { - parent::__construct($indent); + function __construct($user, $cur = null, $indent = true) { + parent::__construct($cur, $indent); $this->user = $user; if (!empty($user)) { $profile = $user->getProfile(); -- cgit v1.2.3-54-g00ecf From 697a9948df3c9d4275b3525227007bfd5a1c5709 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 27 May 2010 14:18:08 -0700 Subject: Ticket #2329: fix for use of _m() translation functions from outside of plugin directories --- lib/language.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/language.php b/lib/language.php index 64b59e739..3846b8f35 100644 --- a/lib/language.php +++ b/lib/language.php @@ -205,12 +205,20 @@ function _mdomain($backtrace) if (DIRECTORY_SEPARATOR !== '/') { $path = strtr($path, DIRECTORY_SEPARATOR, '/'); } - $cut = strpos($path, '/plugins/') + 9; - $cut2 = strpos($path, '/', $cut); - if ($cut && $cut2) { - $cached[$path] = substr($path, $cut, $cut2 - $cut); - } else { + $plug = strpos($path, '/plugins/'); + if ($plug === false) { + // We're not in a plugin; return null for the default domain. return null; + } else { + $cut = $plug + 9; + $cut2 = strpos($path, '/', $cut); + if ($cut2) { + $cached[$path] = substr($path, $cut, $cut2 - $cut); + } else { + // We might be running directly from the plugins dir? + // If so, there's no place to store locale info. + return null; + } } } return $cached[$path]; -- cgit v1.2.3-54-g00ecf From cef302cacdf86d1c82f7937d2901f9254c88bf8a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 28 May 2010 06:22:12 +0000 Subject: Bugfix: api/statuses/destroy.:format was outputting deleted notice twice, causing parsers to fail. --- actions/apistatusesdestroy.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/actions/apistatusesdestroy.php b/actions/apistatusesdestroy.php index f7d52f020..0bfcdd060 100644 --- a/actions/apistatusesdestroy.php +++ b/actions/apistatusesdestroy.php @@ -57,7 +57,7 @@ require_once INSTALLDIR . '/lib/apiauth.php'; class ApiStatusesDestroyAction extends ApiAuthAction { - var $status = null; + var $status = null; /** * Take arguments for running @@ -120,18 +120,11 @@ class ApiStatusesDestroyAction extends ApiAuthAction $replies->get('notice_id', $this->notice_id); $replies->delete(); $this->notice->delete(); - - if ($this->format == 'xml') { - $this->showSingleXmlStatus($this->notice); - } elseif ($this->format == 'json') { - $this->show_single_json_status($this->notice); - } + $this->showNotice(); } else { $this->clientError(_('You may not delete another user\'s status.'), 403, $this->format); } - - $this->showNotice(); } /** -- cgit v1.2.3-54-g00ecf From f4539b52ad2c25a87e906c68d955ef921678e18c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 28 May 2010 16:03:09 -0700 Subject: Ticket 2329 followup: my clever 'let it use the default' was foiled by PHP gettext module not quite exposing a compatible interface as the backend gettext library. (Most funcs squash null domain parameter into '' empty string, which isn't interpreted as 'use the current default'.) --- lib/language.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/language.php b/lib/language.php index 3846b8f35..cb12cca69 100644 --- a/lib/language.php +++ b/lib/language.php @@ -61,7 +61,7 @@ if (!function_exists('dpgettext')) { * Not currently exposed in PHP's gettext module; implemented to be compat * with gettext.h's macros. * - * @param string $domain domain identifier, or null for default domain + * @param string $domain domain identifier * @param string $context context identifier, should be some key like "menu|file" * @param string $msgid English source text * @return string original or translated message @@ -106,7 +106,7 @@ if (!function_exists('dnpgettext')) { * Not currently exposed in PHP's gettext module; implemented to be compat * with gettext.h's macros. * - * @param string $domain domain identifier, or null for default domain + * @param string $domain domain identifier * @param string $context context identifier, should be some key like "menu|file" * @param string $msg singular English source text * @param string $plural plural English source text @@ -180,7 +180,11 @@ function _m($msg/*, ...*/) } /** - * Looks for which plugin we've been called from to set the gettext domain. + * Looks for which plugin we've been called from to set the gettext domain; + * if not in a plugin subdirectory, we'll use the default 'statusnet'. + * + * Note: we can't return null for default domain since most of the PHP gettext + * wrapper functions turn null into "" before passing to the backend library. * * @param array $backtrace debug_backtrace() output * @return string @@ -207,8 +211,8 @@ function _mdomain($backtrace) } $plug = strpos($path, '/plugins/'); if ($plug === false) { - // We're not in a plugin; return null for the default domain. - return null; + // We're not in a plugin; return default domain. + return 'statusnet'; } else { $cut = $plug + 9; $cut2 = strpos($path, '/', $cut); @@ -217,7 +221,7 @@ function _mdomain($backtrace) } else { // We might be running directly from the plugins dir? // If so, there's no place to store locale info. - return null; + return 'statusnet'; } } } -- cgit v1.2.3-54-g00ecf From 58fe1a597c76dd6737abbe44e7cb7111d3ae3375 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 28 May 2010 16:52:17 -0700 Subject: OpenID: add option to enable asking for a username to append to the trusted provider's base URL. Good for hooking up with sites like WikiHow, where usernames are appended to a base URL to get a profile URL which is used as the provider. $config['openid']['append_username'] = true; or check 'Append a username to base URL' in OpenID admin panel. --- plugins/OpenID/openid.php | 2 ++ plugins/OpenID/openidadminpanel.php | 10 ++++++++++ plugins/OpenID/openidlogin.php | 20 +++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/plugins/OpenID/openid.php b/plugins/OpenID/openid.php index 574ecca72..8be02e031 100644 --- a/plugins/OpenID/openid.php +++ b/plugins/OpenID/openid.php @@ -144,8 +144,10 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) // Handle failure status return values. if (!$auth_request) { + common_log(LOG_ERR, __METHOD__ . ": mystery fail contacting $openid_url"); return _m('Not a valid OpenID.'); } else if (Auth_OpenID::isFailure($auth_request)) { + common_log(LOG_ERR, __METHOD__ . ": OpenID fail to $openid_url: $auth_request->message"); return sprintf(_m('OpenID failure: %s'), $auth_request->message); } diff --git a/plugins/OpenID/openidadminpanel.php b/plugins/OpenID/openidadminpanel.php index 063306366..ce4806cc8 100644 --- a/plugins/OpenID/openidadminpanel.php +++ b/plugins/OpenID/openidadminpanel.php @@ -91,6 +91,7 @@ class OpenidadminpanelAction extends AdminPanelAction ); static $booleans = array( + 'openid' => array('append_username'), 'site' => array('openidonly') ); @@ -222,6 +223,15 @@ class OpenIDAdminPanelForm extends AdminForm ); $this->unli(); + $this->li(); + $this->out->checkbox( + 'append_username', _m('Append a username to base URL'), + (bool) $this->value('append_username', 'openid'), + _m('Login form will show the base URL and prompt for a username to add at the end. Use when OpenID provider URL should be the profile page for individual users.'), + 'true' + ); + $this->unli(); + $this->li(); $this->input( 'required_team', diff --git a/plugins/OpenID/openidlogin.php b/plugins/OpenID/openidlogin.php index 8c559c934..ffedc6481 100644 --- a/plugins/OpenID/openidlogin.php +++ b/plugins/OpenID/openidlogin.php @@ -32,6 +32,9 @@ class OpenidloginAction extends Action $provider = common_config('openid', 'trusted_provider'); if ($provider) { $openid_url = $provider; + if (common_config('openid', 'append_username')) { + $openid_url .= $this->trimmed('openid_username'); + } } else { $openid_url = $this->trimmed('openid_url'); } @@ -94,7 +97,15 @@ class OpenidloginAction extends Action function showScripts() { parent::showScripts(); - $this->autofocus('openid_url'); + if (common_config('openid', 'trusted_provider')) { + if (common_config('openid', 'append_username')) { + $this->autofocus('openid_username'); + } else { + $this->autofocus('rememberme'); + } + } else { + $this->autofocus('openid_url'); + } } function title() @@ -122,10 +133,17 @@ class OpenidloginAction extends Action $this->elementStart('ul', 'form_data'); $this->elementStart('li'); $provider = common_config('openid', 'trusted_provider'); + $appendUsername = common_config('openid', 'append_username'); if ($provider) { $this->element('label', array(), _m('OpenID provider')); $this->element('span', array(), $provider); + if ($appendUsername) { + $this->element('input', array('id' => 'openid_username', + 'name' => 'openid_username', + 'style' => 'float: none')); + } $this->element('p', 'form_guide', + ($appendUsername ? _m('Enter your username.') . ' ' : '') . _m('You will be sent to the provider\'s site for authentication.')); $this->hidden('openid_url', $provider); } else { -- cgit v1.2.3-54-g00ecf From 83b976f7eafb74e2ef675262b427be43039428b9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 31 May 2010 15:48:24 -0700 Subject: Added DarterosStatus to notice sources --- db/notice_source.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/db/notice_source.sql b/db/notice_source.sql index fbcdd6568..5d8664631 100644 --- a/db/notice_source.sql +++ b/db/notice_source.sql @@ -9,6 +9,7 @@ VALUES ('bti','bti','http://gregkh.github.com/bti/', now()), ('choqok', 'Choqok', 'http://choqok.gnufolks.org/', now()), ('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()), + ('DarterosStatus', 'Darteros Status', 'http://www.darteros.com/doc/Darteros_Status', now()), ('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()), ('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()), ('drupal','Drupal','http://drupal.org/', now()), -- cgit v1.2.3-54-g00ecf From b0c589de9aa7bfd41bd59e12ff16d0791009fb18 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 1 Jun 2010 18:29:01 +0000 Subject: Ticket #2330: fix Google Maps provider for Mapstraction plugin --- plugins/Mapstraction/MapstractionPlugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/Mapstraction/MapstractionPlugin.php b/plugins/Mapstraction/MapstractionPlugin.php index 868933fd4..e7240a644 100644 --- a/plugins/Mapstraction/MapstractionPlugin.php +++ b/plugins/Mapstraction/MapstractionPlugin.php @@ -125,8 +125,8 @@ class MapstractionPlugin extends Plugin $action->script('http://tile.cloudmade.com/wml/0.2/web-maps-lite.js'); break; case 'google': - $action->script(sprintf('http://maps.google.com/maps?file=api&v=2&sensor=false&key=%s', - $this->apikey)); + $action->script(sprintf('http://maps.google.com/maps?file=api&v=2&sensor=false&key=%s', + urlencode($this->apikey))); break; case 'microsoft': $action->script('http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6'); @@ -137,7 +137,7 @@ class MapstractionPlugin extends Plugin break; case 'yahoo': $action->script(sprintf('http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=%s', - $this->apikey)); + urlencode($this->apikey))); break; case 'geocommons': // don't support this yet default: -- cgit v1.2.3-54-g00ecf From 634752f0d262b4fb02456889250378fca084cd2e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 1 Jun 2010 18:41:17 +0000 Subject: Mapstraction plugin fix: set icon dimensions (24x24 px); Google Maps provider otherwise defaults to stretching them to a funny shape instead of showing square avatars. --- plugins/Mapstraction/usermap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Mapstraction/usermap.js b/plugins/Mapstraction/usermap.js index 4b7a6c26b..53cfe6bb0 100644 --- a/plugins/Mapstraction/usermap.js +++ b/plugins/Mapstraction/usermap.js @@ -104,7 +104,7 @@ function showMapstraction(element, notices) { pt = new mxn.LatLonPoint(lat, lon); mkr = new mxn.Marker(pt); - mkr.setIcon(n['user']['profile_image_url']); + mkr.setIcon(n['user']['profile_image_url'], [24, 24]); mkr.setInfoBubble('' + n['user']['screen_name'] + '' + ' ' + n['html'] + '
'+ n['created_at'] + ''); -- cgit v1.2.3-54-g00ecf