From 8545a1c5fe65e056b4dd7fca5464cc927a43b38a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 20 May 2009 06:46:11 +0000 Subject: [PATCH] Reorganized some stuff and made new Facebook Login tab --- plugins/FBConnect/FBCLoginGroupNav.php | 112 ++++++++ plugins/FBConnect/FBConnectAuth.php | 370 +++++++++++++++++++++++++ plugins/FBConnect/FBConnectLogin.php | 362 ++---------------------- plugins/FBConnect/FBConnectPlugin.php | 39 ++- 4 files changed, 546 insertions(+), 337 deletions(-) create mode 100644 plugins/FBConnect/FBCLoginGroupNav.php create mode 100644 plugins/FBConnect/FBConnectAuth.php diff --git a/plugins/FBConnect/FBCLoginGroupNav.php b/plugins/FBConnect/FBCLoginGroupNav.php new file mode 100644 index 0000000000..9aa01a0940 --- /dev/null +++ b/plugins/FBConnect/FBCLoginGroupNav.php @@ -0,0 +1,112 @@ +. + * + * @category Menu + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/lib/widget.php'; + +/** + * Menu for login group of actions + * + * @category Output + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Widget + */ + +class FBCLoginGroupNav extends Widget +{ + var $action = null; + + /** + * Construction + * + * @param Action $action current action, used for output + */ + + function __construct($action=null) + { + parent::__construct($action); + $this->action = $action; + } + + /** + * Show the menu + * + * @return void + */ + + function show() + { + common_debug('FBCLoginGroupNav'); + + $this->action->elementStart('dl', array('id' => 'site_nav_local_views')); + $this->action->element('dt', null, _('Local views')); + $this->action->elementStart('dd'); + + // action => array('prompt', 'title') + $menu = array(); + + $menu['login'] = array(_('Login'), + _('Login with a username and password')); + + if (!(common_config('site','closed') || common_config('site','inviteonly'))) { + $menu['register'] = array(_('Register'), + _('Sign up for a new account')); + } + + $menu['openidlogin'] = array(_('OpenID'), + _('Login or register with OpenID')); + + $menu['FBConnectLogin'] = array(_('Facebook'), + _('Login or register using Facebook')); + + $action_name = $this->action->trimmed('action'); + $this->action->elementStart('ul', array('class' => 'nav')); + + foreach ($menu as $menuaction => $menudesc) { + $this->action->menuItem(common_local_url($menuaction), + $menudesc[0], + $menudesc[1], + $action_name === $menuaction); + } + + $this->action->elementEnd('ul'); + + $this->action->elementEnd('dd'); + $this->action->elementEnd('dl'); + } +} diff --git a/plugins/FBConnect/FBConnectAuth.php b/plugins/FBConnect/FBConnectAuth.php new file mode 100644 index 0000000000..0dc016c05c --- /dev/null +++ b/plugins/FBConnect/FBConnectAuth.php @@ -0,0 +1,370 @@ +. + * + * @category Plugin + * @package Laconica + * @author Zach Copley + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php'; + +class FbconnectauthAction extends Action +{ + + var $fbuid = null; + var $fb_fields = null; + + function prepare($args) { + parent::prepare($args); + + $this->fbuid = getFacebook()->get_loggedin_user(); + $this->fb_fields = $this->getFacebookFields($this->fbuid, + array('first_name', 'last_name', 'name')); + + return true; + } + + function handle($args) + { + parent::handle($args); + + if (common_is_real_login()) { + $this->clientError(_('Already logged in.')); + } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->showForm(_('There was a problem with your session token. Try again, please.')); + return; + } + if ($this->arg('create')) { + if (!$this->boolean('license')) { + $this->showForm(_('You can\'t register if you don\'t agree to the license.'), + $this->trimmed('newname')); + return; + } + $this->createNewUser(); + } else if ($this->arg('connect')) { + $this->connectUser(); + } else { + common_debug(print_r($this->args, true), __FILE__); + $this->showForm(_('Something weird happened.'), + $this->trimmed('newname')); + } + } else { + $this->tryLogin(); + } + } + + function showPageNotice() + { + if ($this->error) { + $this->element('div', array('class' => 'error'), $this->error); + } else { + $this->element('div', 'instructions', + sprintf(_('This is the first time you\'ve logged into %s so we must connect your Facebook to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name'))); + } + } + + function title() + { + return _('Facebook Account Setup'); + } + + function showForm($error=null, $username=null) + { + $this->error = $error; + $this->username = $username; + + $this->showPage(); + } + + function showPage() + { + parent::showPage(); + } + + function showContent() + { + if (!empty($this->message_text)) { + $this->element('p', null, $this->message); + return; + } + + $this->elementStart('form', array('method' => 'post', + 'id' => 'account_connect', + 'action' => common_local_url('fbconnectlogin'))); + $this->hidden('token', common_session_token()); + $this->element('h2', null, + _('Create new account')); + $this->element('p', null, + _('Create a new user with this nickname.')); + $this->input('newname', _('New nickname'), + ($this->username) ? $this->username : '', + _('1-64 lowercase letters or numbers, no punctuation or spaces')); + $this->elementStart('p'); + $this->element('input', array('type' => 'checkbox', + 'id' => 'license', + 'name' => 'license', + 'value' => 'true')); + $this->text(_('My text and files are available under ')); + $this->element('a', array('href' => common_config('license', 'url')), + common_config('license', 'title')); + $this->text(_(' except this private data: password, email address, IM address, phone number.')); + $this->elementEnd('p'); + $this->submit('create', _('Create')); + $this->element('h2', null, + _('Connect existing account')); + $this->element('p', null, + _('If you already have an account, login with your username and password to connect it to your Facebook.')); + $this->input('nickname', _('Existing nickname')); + $this->password('password', _('Password')); + $this->submit('connect', _('Connect')); + $this->elementEnd('form'); + } + + function message($msg) + { + $this->message_text = $msg; + $this->showPage(); + } + + function createNewUser() + { + + if (common_config('site', 'closed')) { + $this->clientError(_('Registration not allowed.')); + return; + } + + $invite = null; + + if (common_config('site', 'inviteonly')) { + $code = $_SESSION['invitecode']; + if (empty($code)) { + $this->clientError(_('Registration not allowed.')); + return; + } + + $invite = Invitation::staticGet($code); + + if (empty($invite)) { + $this->clientError(_('Not a valid invitation code.')); + return; + } + } + + $nickname = $this->trimmed('newname'); + + if (!Validate::string($nickname, array('min_length' => 1, + 'max_length' => 64, + 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { + $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.')); + return; + } + + if (!User::allowed_nickname($nickname)) { + $this->showForm(_('Nickname not allowed.')); + return; + } + + if (User::staticGet('nickname', $nickname)) { + $this->showForm(_('Nickname already in use. Try another one.')); + return; + } + + $fullname = trim($this->fb_fields['firstname'] . + ' ' . $this->fb_fields['lastname']); + + $args = array('nickname' => $nickname, 'fullname' => $fullname); + + if (!empty($invite)) { + $args['code'] = $invite->code; + } + + $user = User::register($args); + + $result = $this->flinkUser($user->id, $this->fbuid); + + if (!$result) { + $this->serverError(_('Error connecting user to Facebook.')); + return; + } + + common_set_user($user); + common_real_login(true); + + common_debug("Registered new user $user->id from Facebook user $this->fbuid"); + + common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)), + 303); + } + + function connectUser() + { + $nickname = $this->trimmed('nickname'); + $password = $this->trimmed('password'); + + if (!common_check_user($nickname, $password)) { + $this->showForm(_('Invalid username or password.')); + return; + } + + $user = User::staticGet('nickname', $nickname); + + if ($user) { + common_debug("Legit user to connect to Facebook: $nickname"); + } + + $result = $this->flinkUser($user->id, $this->fbuid); + + if (!$result) { + $this->serverError(_('Error connecting user to Facebook.')); + return; + } + + common_debug("Connected Facebook user $this->fbuid to local user $user->id"); + + common_set_user($user); + common_real_login(true); + + $this->goHome($user->nickname); + } + + function tryLogin() + { + common_debug("Trying Facebook Login..."); + + $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); + + if ($flink) { + $user = $flink->getUser(); + + if ($user) { + + common_debug("Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)"); + + common_set_user($user); + common_real_login(true); + $this->goHome($user->nickname); + } + + } else { + $this->showForm(null, $this->bestNewNickname()); + } + } + + function goHome($nickname) + { + $url = common_get_returnto(); + if ($url) { + // We don't have to return to it again + common_set_returnto(null); + } else { + $url = common_local_url('all', + array('nickname' => + $nickname)); + } + + common_redirect($url, 303); + } + + function flinkUser($user_id, $fbuid) + { + $flink = new Foreign_link(); + $flink->user_id = $user_id; + $flink->foreign_id = $fbuid; + $flink->service = FACEBOOK_SERVICE; + $flink->created = common_sql_now(); + + $flink_id = $flink->insert(); + + return $flink_id; + } + + function bestNewNickname() + { + if (!empty($this->fb_fields['name'])) { + $nickname = $this->nicknamize($this->fb_fields['name']); + if ($this->isNewNickname($nickname)) { + return $nickname; + } + } + + // Try the full name + + $fullname = trim($this->fb_fields['firstname'] . + ' ' . $this->fb_fields['lastname']); + + if (!empty($fullname)) { + $fullname = $this->nicknamize($fullname); + if ($this->isNewNickname($fullname)) { + return $fullname; + } + } + + return null; + } + + // Given a string, try to make it work as a nickname + + function nicknamize($str) + { + $str = preg_replace('/\W/', '', $str); + return strtolower($str); + } + + function isNewNickname($str) + { + if (!Validate::string($str, array('min_length' => 1, + 'max_length' => 64, + 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { + return false; + } + if (!User::allowed_nickname($str)) { + return false; + } + if (User::staticGet('nickname', $str)) { + return false; + } + return true; + } + + // XXX: Consider moving this to lib/facebookutil.php + function getFacebookFields($fb_uid, $fields) { + try { + $infos = getFacebook()->api_client->users_getInfo($fb_uid, $fields); + + if (empty($infos)) { + return null; + } + return reset($infos); + + } catch (Exception $e) { + error_log("Failure in the api when requesting " . join(",", $fields) + ." on uid " . $fb_uid . " : ". $e->getMessage()); + return null; + } + } + +} diff --git a/plugins/FBConnect/FBConnectLogin.php b/plugins/FBConnect/FBConnectLogin.php index c2a2885717..70710eb709 100644 --- a/plugins/FBConnect/FBConnectLogin.php +++ b/plugins/FBConnect/FBConnectLogin.php @@ -1,12 +1,9 @@ . - * - * @category Plugin - * @package Laconica - * @author Zach Copley - * @copyright 2009 Control Yourself, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ */ -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php'; -require_once INSTALLDIR . '/lib/facebookutil.php'; +if (!defined('LACONICA')) { + exit(1); +} -class FBConnectloginAction extends Action +require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php'; + +class FBConnectLoginAction extends Action { - - var $fbuid = null; - var $fb_fields = null; - - function prepare($args) { - parent::prepare($args); - - $this->fbuid = getFacebook()->get_loggedin_user(); - $this->fb_fields = $this->getFacebookFields($this->fbuid, - array('first_name', 'last_name', 'name')); - - return true; - } - function handle($args) { parent::handle($args); if (common_is_real_login()) { $this->clientError(_('Already logged in.')); - } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. Try again, please.')); - return; - } - if ($this->arg('create')) { - if (!$this->boolean('license')) { - $this->showForm(_('You can\'t register if you don\'t agree to the license.'), - $this->trimmed('newname')); - return; - } - $this->createNewUser(); - } else if ($this->arg('connect')) { - $this->connectUser(); - } else { - common_debug(print_r($this->args, true), __FILE__); - $this->showForm(_('Something weird happened.'), - $this->trimmed('newname')); - } - } else { - $this->tryLogin(); - } + } + + $this->showPage(); + } + + function getInstructions() + { + return _('Login with your Facebook Account'); } function showPageNotice() { - if ($this->error) { - $this->element('div', array('class' => 'error'), $this->error); - } else { - $this->element('div', 'instructions', - sprintf(_('This is the first time you\'ve logged into %s so we must connect your Facebook to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name'))); - } + $instr = $this->getInstructions(); + $output = common_markup_to_html($instr); + $this->elementStart('div', 'instructions'); + $this->raw($output); + $this->elementEnd('div'); } function title() { - return _('Facebook Account Setup'); + return _('Facebook Login'); } - function showForm($error=null, $username=null) - { - $this->error = $error; - $this->username = $username; + function showContent() { - $this->showPage(); - } + $this->elementStart('fieldset'); + - function showPage() - { - parent::showPage(); - } + $this->element('fb:login-button', array('onlogin' => 'goto_login()', + 'length' => 'long')); - function showContent() - { - if (!empty($this->message_text)) { - $this->element('p', null, $this->message); - return; - } - - $this->elementStart('form', array('method' => 'post', - 'id' => 'account_connect', - 'action' => common_local_url('fbconnectlogin'))); - $this->hidden('token', common_session_token()); - $this->element('h2', null, - _('Create new account')); - $this->element('p', null, - _('Create a new user with this nickname.')); - $this->input('newname', _('New nickname'), - ($this->username) ? $this->username : '', - _('1-64 lowercase letters or numbers, no punctuation or spaces')); - $this->elementStart('p'); - $this->element('input', array('type' => 'checkbox', - 'id' => 'license', - 'name' => 'license', - 'value' => 'true')); - $this->text(_('My text and files are available under ')); - $this->element('a', array('href' => common_config('license', 'url')), - common_config('license', 'title')); - $this->text(_(' except this private data: password, email address, IM address, phone number.')); - $this->elementEnd('p'); - $this->submit('create', _('Create')); - $this->element('h2', null, - _('Connect existing account')); - $this->element('p', null, - _('If you already have an account, login with your username and password to connect it to your Facebook.')); - $this->input('nickname', _('Existing nickname')); - $this->password('password', _('Password')); - $this->submit('connect', _('Connect')); - $this->elementEnd('form'); - } - - function message($msg) - { - $this->message_text = $msg; - $this->showPage(); - } - - function createNewUser() - { - - if (common_config('site', 'closed')) { - $this->clientError(_('Registration not allowed.')); - return; - } - - $invite = null; - - if (common_config('site', 'inviteonly')) { - $code = $_SESSION['invitecode']; - if (empty($code)) { - $this->clientError(_('Registration not allowed.')); - return; - } - - $invite = Invitation::staticGet($code); - - if (empty($invite)) { - $this->clientError(_('Not a valid invitation code.')); - return; - } - } - - $nickname = $this->trimmed('newname'); - - if (!Validate::string($nickname, array('min_length' => 1, - 'max_length' => 64, - 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { - $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.')); - return; - } - - if (!User::allowed_nickname($nickname)) { - $this->showForm(_('Nickname not allowed.')); - return; - } - - if (User::staticGet('nickname', $nickname)) { - $this->showForm(_('Nickname already in use. Try another one.')); - return; - } - - $fullname = trim($this->fb_fields['firstname'] . - ' ' . $this->fb_fields['lastname']); - - $args = array('nickname' => $nickname, 'fullname' => $fullname); - - if (!empty($invite)) { - $args['code'] = $invite->code; - } - - $user = User::register($args); - - $result = $this->flinkUser($user->id, $this->fbuid); - - if (!$result) { - $this->serverError(_('Error connecting user to Facebook.')); - return; - } - - common_set_user($user); - common_real_login(true); - - common_debug("Registered new user $user->id from Facebook user $this->fbuid"); - - common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)), - 303); - } - - function connectUser() - { - $nickname = $this->trimmed('nickname'); - $password = $this->trimmed('password'); - - if (!common_check_user($nickname, $password)) { - $this->showForm(_('Invalid username or password.')); - return; - } - - $user = User::staticGet('nickname', $nickname); - - if ($user) { - common_debug("Legit user to connect to Facebook: $nickname"); - } - - $result = $this->flinkUser($user->id, $this->fbuid); - - if (!$result) { - $this->serverError(_('Error connecting user to Facebook.')); - return; - } - - common_debug("Connected Facebook user $this->fbuid to local user $user->id"); - - common_set_user($user); - common_real_login(true); - - $this->goHome($user->nickname); - } - - function tryLogin() - { - common_debug("Trying Facebook Login..."); - - $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); - - if ($flink) { - $user = $flink->getUser(); - - if ($user) { - - common_debug("Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)"); - - common_set_user($user); - common_real_login(true); - $this->goHome($user->nickname); - } - - } else { - $this->showForm(null, $this->bestNewNickname()); - } - } - - function goHome($nickname) - { - $url = common_get_returnto(); - if ($url) { - // We don't have to return to it again - common_set_returnto(null); - } else { - $url = common_local_url('all', - array('nickname' => - $nickname)); - } - - common_redirect($url, 303); - } - - function flinkUser($user_id, $fbuid) - { - $flink = new Foreign_link(); - $flink->user_id = $user_id; - $flink->foreign_id = $fbuid; - $flink->service = FACEBOOK_SERVICE; - $flink->created = common_sql_now(); - - $flink_id = $flink->insert(); - - return $flink_id; - } - - function bestNewNickname() - { - if (!empty($this->fb_fields['name'])) { - $nickname = $this->nicknamize($this->fb_fields['name']); - if ($this->isNewNickname($nickname)) { - return $nickname; - } - } - - // Try the full name - - $fullname = trim($this->fb_fields['firstname'] . - ' ' . $this->fb_fields['lastname']); - - if (!empty($fullname)) { - $fullname = $this->nicknamize($fullname); - if ($this->isNewNickname($fullname)) { - return $fullname; - } - } - - return null; - } - - // Given a string, try to make it work as a nickname - - function nicknamize($str) - { - $str = preg_replace('/\W/', '', $str); - return strtolower($str); - } - - function isNewNickname($str) - { - if (!Validate::string($str, array('min_length' => 1, - 'max_length' => 64, - 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { - return false; - } - if (!User::allowed_nickname($str)) { - return false; - } - if (User::staticGet('nickname', $str)) { - return false; - } - return true; - } - - // XXX: Consider moving this to lib/facebookutil.php - function getFacebookFields($fb_uid, $fields) { - try { - $infos = getFacebook()->api_client->users_getInfo($fb_uid, $fields); - - if (empty($infos)) { - return null; - } - return reset($infos); - - } catch (Exception $e) { - error_log("Failure in the api when requesting " . join(",", $fields) - ." on uid " . $fb_uid . " : ". $e->getMessage()); - return null; - } + $this->elementEnd('fieldset'); } } diff --git a/plugins/FBConnect/FBConnectPlugin.php b/plugins/FBConnect/FBConnectPlugin.php index 191cede765..079270510d 100644 --- a/plugins/FBConnect/FBConnectPlugin.php +++ b/plugins/FBConnect/FBConnectPlugin.php @@ -31,8 +31,10 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php'; require_once INSTALLDIR . '/lib/facebookutil.php'; +require_once INSTALLDIR . '/plugins/FBConnect/FBConnectAuth.php'; +require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php'; +require_once INSTALLDIR . '/plugins/FBConnect/FBCLoginGroupNav.php'; /** * Plugin to enable Facebook Connect @@ -54,7 +56,11 @@ class FBConnectPlugin extends Plugin // Hook in new actions function onRouterInitialized(&$m) { - $m->connect('main/facebookconnect', array('action' => 'fbconnectlogin')); + + common_debug("onRouterIntialized()"); + + $m->connect('main/facebookconnect', array('action' => 'FBConnectAuth')); + $m->connect('main/facebooklogin', array('action' => 'FBConnectLogin')); } // Add in xmlns:fb @@ -67,8 +73,10 @@ class FBConnectPlugin extends Plugin $name = get_class($action); + common_debug("onStartShowHTML: action = $name"); + // Avoid a redirect loop - if (!in_array($name, array('FBConnectloginAction', 'ClientErrorAction'))) { + if (!in_array($name, array('FBConnectAuthAction', 'ClientErrorAction'))) { $this->checkFacebookUser($action); @@ -246,7 +254,7 @@ class FBConnectPlugin extends Plugin } else { common_debug("Facebook user is NOT logged in."); - common_redirect(common_local_url('fbconnectlogin'), 303); + common_redirect(common_local_url('FBConnectAuth'), 303); } } else { @@ -259,7 +267,28 @@ class FBConnectPlugin extends Plugin } } - + + function onStartShowLocalNavBlock($action) + { + $action_name = get_class($action); + + common_debug($action_name); + + $login_actions = array('LoginAction', 'RegisterAction', + 'OpenidloginAction', 'FacebookStart'); + + if (in_array($action_name, $login_actions)) { + + common_debug("LoginAction found!"); + + $nav = new FBCLoginGroupNav($action); + $nav->show(); + return false; + } + + return true; + + } }