From ea0b6a4508093560d7681c1adf6a4720982c2a53 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Fri, 15 Jun 2012 15:47:09 +0000 Subject: [PATCH 01/18] Updating for Kohana 3.2; Adding model fields as a class property for easier overriding; Deleting associated user roles on deletion; Adding config variable to turn off registration and allow only login --- classes/useradmin/auth/orm.php | 15 +- classes/useradmin/controller/admin/user.php | 186 ++++++++++---------- classes/useradmin/controller/app.php | 2 +- classes/useradmin/controller/user.php | 60 ++++--- classes/useradmin/provider/facebook.php | 9 +- classes/useradmin/provider/twitter.php | 5 +- views/template/useradmin.php | 22 +-- views/user/login.php | 47 ++--- 8 files changed, 192 insertions(+), 154 deletions(-) diff --git a/classes/useradmin/auth/orm.php b/classes/useradmin/auth/orm.php index fcfbc64..d6f3913 100644 --- a/classes/useradmin/auth/orm.php +++ b/classes/useradmin/auth/orm.php @@ -7,6 +7,15 @@ * @author Gabriel R. Giannattasio */ class Useradmin_Auth_ORM extends Kohana_Auth_ORM implements Useradmin_Driver_iAuth { + + /** User Model Fields + * Override in your app to add fields + */ + public $user_model_fields = array( + 'username', + 'password', + 'email', + ); /** * Extends the Kohana Auth ORM driver to give useradmin module extras @@ -84,11 +93,7 @@ public function register($fields) } try { - $user->create_user($fields, array( - 'username', - 'password', - 'email', - )); + $user->create_user($fields, $this->user_model_fields); // Add the login role to the user (add a row to the db) $login_role = new Model_Role(array('name' =>'login')); $user->add('roles', $login_role); diff --git a/classes/useradmin/controller/admin/user.php b/classes/useradmin/controller/admin/user.php index e9e6dff..5138618 100644 --- a/classes/useradmin/controller/admin/user.php +++ b/classes/useradmin/controller/admin/user.php @@ -1,121 +1,127 @@ 'admin' will only allow users with the role admin to access action_adminpanel - * 'moderatorpanel' => array('login', 'moderator') will only allow users with the roles login and moderator to access action_moderatorpanel + /** Controls access for separate actions + * + * See Controller_App for how this implemented. + * + * Examples: + * 'adminpanel' => 'admin' will only allow users with the role admin to access action_adminpanel + * 'moderatorpanel' => array('login', 'moderator') will only allow users with the roles login and moderator to access action_moderatorpanel */ public $secure_actions = array(); + + /** User Model Fields + * Override in your app to add fields + */ + public $user_model_fields = array( + 'username', + 'password', + 'email' + ); - // USER ADMINISTRATION - /** - * Administator view of users. + // USER ADMINISTRATION + /** + * Administator view of users. */ public function action_index() { - // set the template title (see Controller_App for implementation) + // set the template title (see Controller_App for implementation) $this->template->title = __('User administration'); - // create a user + // create a user $user = ORM::factory('user'); - // This is an example of how to use Kohana pagination - // Get the total count for the pagination + // This is an example of how to use Kohana pagination + // Get the total count for the pagination $total = $user->count_all(); - // Create a paginator + // Create a paginator $pagination = new Pagination(array( 'total_items' => $total, - 'items_per_page' => 30, // set this to 30 or 15 for the real thing, now just for testing purposes... + 'items_per_page' => 30, // set this to 30 or 15 for the real thing, now just for testing purposes... 'auto_hide' => false, 'view' => 'pagination/useradmin' )); - // Get the items for the query - $sort = isset($_GET['sort']) ? $_GET['sort'] : 'username'; // set default sorting direction here + // Get the items for the query + $sort = isset($_GET['sort']) ? $_GET['sort'] : 'username'; // set default sorting direction here $dir = isset($_GET['dir']) ? 'DESC' : 'ASC'; $result = $user->limit($pagination->items_per_page) ->offset($pagination->offset) ->order_by($sort, $dir) ->find_all(); - // render view - // pass the paginator, result and default sorting direction + // render view + // pass the paginator, result and default sorting direction $this->template->content = View::factory('user/admin/index') ->set('users', $result) ->set('paging', $pagination) ->set('default_sort', $sort); } - /** - * Administrator edit user. - * @param string $id - * @return void + /** + * Administrator edit user. + * @param string $id + * @return void */ - public function action_edit($id = NULL) + public function action_edit() { - // set the template title (see Controller_App for implementation) + $id = $this->request->param('id'); + // set the template title (see Controller_App for implementation) $this->template->title = __('Edit user'); - // load the content from view + // load the content from view $view = View::factory('user/admin/edit'); - // save the data + // save the data if (! empty($_POST)) { - //FIXME: Use Model_User in the controller insteat ORM::factory() for model generic driver compatibility - // sample code paths for edit and create + //FIXME: Use Model_User in the controller insteat ORM::factory() for model generic driver compatibility + // sample code paths for edit and create if (is_numeric($id)) { - // EDIT: load the model with ID + // EDIT: load the model with ID $user = ORM::factory('user', $id); } else { - // CREATE: do not specify id + // CREATE: do not specify id $user = ORM::factory('user'); } if (empty($_POST['password']) || empty($_POST['password_confirm'])) { - // force unsetting the password! Otherwise Kohana3 will automatically hash the empty string - preventing logins + // force unsetting the password! Otherwise Kohana3 will automatically hash the empty string - preventing logins unset($_POST['password'], $_POST['password_confirm']); } - // you can't change your user id + // you can't change your user id unset($_POST['id']); $user->values($_POST); - // since we combine both editing and creating here we need a separate variable - // you can get rid of it if your actions don't need to do that + // since we combine both editing and creating here we need a separate variable + // you can get rid of it if your actions don't need to do that $result = false; $errors = null; if (is_numeric($id)) { - // EDIT: check using alternative rules + // EDIT: check using alternative rules try { - $user->update_user($_POST, array( - 'username', - 'password', - 'email' - )); + $user->update_user($_POST, $this->user_model_fields); $result = true; } catch (ORM_Validation_Exception $e) @@ -126,14 +132,10 @@ public function action_edit($id = NULL) } else { - // CREATE: check using default rules + // CREATE: check using default rules try { - $user->create_user($_POST, array( - 'username', - 'password', - 'email' - )); + $user->create_user($_POST, $this->user_model_fields); $result = true; } catch (ORM_Validation_Exception $e) @@ -144,45 +146,45 @@ public function action_edit($id = NULL) } if ($result) { - // roles have to be added separately, and all users have to have the login role - // you first have to remove the items, otherwise add() will try to add duplicates + // roles have to be added separately, and all users have to have the login role + // you first have to remove the items, otherwise add() will try to add duplicates if (is_numeric($id)) { - // could also use array_diff, but this is much simpler + // could also use array_diff, but this is much simpler DB::delete('roles_users')->where('user_id', '=', $id) ->execute(); } foreach ($_POST['roles'] as $role) { - // add() executes the query immediately, and saves the data (unlike the KO2 docs say) + // add() executes the query immediately, and saves the data (unlike the KO2 docs say) $user->add('roles', ORM::factory('role')->where('name', '=', $role) ->find() ); } - // message: save success + // message: save success Message::add('success', __('Values saved.')); - // redirect and exit + // redirect and exit Request::current()->redirect('admin_user/index'); return; } else { - // Get errors for display in view --> to AppForm + // Get errors for display in view --> to AppForm Message::add('error', __('Error: Values could not be saved.')); - // Note how the first param is the path to the message file (e.g. /messages/register.php) + // Note how the first param is the path to the message file (e.g. /messages/register.php) $view->set('errors', $errors); - // Pass on the old form values --> to AppForm + // Pass on the old form values --> to AppForm $view->set('data', $user->as_array()); } } - // if an ID is set, load the information + // if an ID is set, load the information if (is_numeric($id)) { - // instantiatiate a new model + // instantiatiate a new model $user = ORM::factory('user', $id); $view->set('data', $user->as_array()); - // retrieve roles into array + // retrieve roles into array $roles = array(); foreach ($user->roles->find_all() as $role) { @@ -196,10 +198,10 @@ public function action_edit($id = NULL) 'login' => 'login' )); } - // get all roles + // get all roles $all_roles = array(); $role_model = ORM::factory('role'); - foreach ($role_model->find_all() as $role) + foreach ($role_model->order_by('name')->find_all() as $role) { $all_roles[$role->name] = $role->description; } @@ -208,40 +210,44 @@ public function action_edit($id = NULL) $this->template->content = $view; } - /** - * Administrator delete user - * @param string $id - * @return void + /** + * Administrator delete user + * @param string $id + * @return void */ - public function action_delete($id = NULL) + public function action_delete() { - // set the template title (see Controller_App for implementation) + $id = $this->request->param('id'); + // set the template title (see Controller_App for implementation) $this->template->title = __('Delete user'); $user = ORM::factory('user', $id); - // check for confirmation + // check for confirmation if (is_numeric($id) && isset($_POST['confirmation']) && $_POST['confirmation'] == 'Y') { if ($user->loaded()) { - // Delete the user + // Delete the user $user->delete($id); - // Delete any associated identities - DB::delete('user_identity')->where('user_id', '=', $id) + // Delete any associated identities + DB::delete('user_identities')->where('user_id', '=', $id) + ->execute(); + // Delete any associated roles + DB::delete('roles_users')->where('user_id', '=', $id) ->execute(); - // message: save success + // message: save success Message::add('success', __('User deleted.')); } else { Message::add('success', __('User is already deleted.')); } - // redirect and exit + // redirect and exit Request::current()->redirect('admin_user/index'); return; } - // display confirmation + // display confirmation $this->template->content = View::factory('user/admin/delete') ->set('id', $id) ->set('data',array('username' => $user->username)); } -} +} diff --git a/classes/useradmin/controller/app.php b/classes/useradmin/controller/app.php index 5195fcb..b1693aa 100644 --- a/classes/useradmin/controller/app.php +++ b/classes/useradmin/controller/app.php @@ -52,7 +52,7 @@ class Useradmin_Controller_App extends Controller { */ public function access_required() { - $this->request->redirect('user/noaccess'); + Request::current()->redirect('user/noaccess'); } /** diff --git a/classes/useradmin/controller/user.php b/classes/useradmin/controller/user.php index c7a14a1..15c9b50 100644 --- a/classes/useradmin/controller/user.php +++ b/classes/useradmin/controller/user.php @@ -40,11 +40,20 @@ class Useradmin_Controller_User extends Controller_App { 'change_password' => 'login' ); // the others are public (forgot, login, register, reset, noaccess) // logout is also public to avoid confusion (e.g. easier to specify and test post-logout page) + + /** User Model Fields + * Override in your app to add fields + */ + public $user_model_fields = array( + 'username', + 'password', + 'email' + ); public function before(){ $baseUrl = Url::base(true); if(substr($this->request->referrer(),0,strlen($baseUrl)) == $baseUrl){ - $urlPath = ltrim(parse_url($this->request->referrer(),PHP_URL_PATH),'/'); + $urlPath = str_replace($baseUrl,'',$this->request->referrer()); $processedRef = Request::process_uri($urlPath); $referrerController = Arr::path( $processedRef, @@ -126,12 +135,7 @@ public function action_profile_edit() } try { - $user->update_user($_POST, - array( - 'username', - 'password', - 'email' - )); + $user->update_user($_POST, $this->user_model_fields); // message: save success Message::add('success', __('Values saved.')); // redirect and exit @@ -172,6 +176,8 @@ public function action_profile_edit() */ public function action_register() { + if(!Kohana::$config->load('useradmin.register_enabled')) + $this->request->redirect('user/login'); // Load reCaptcha if needed if (Kohana::$config->load('useradmin')->captcha) { @@ -274,8 +280,11 @@ public function action_unregister() } // Delete the user $user->delete($id); + // Delete any associated roles + DB::delete('roles_users')->where('user_id', '=', $id) + ->execute(); // Delete any associated identities - DB::delete('user_identity')->where('user_id', '=', $id) + DB::delete('user_identities')->where('user_id', '=', $id) ->execute(); // message: save success Message::add('success', __('User deleted.')); @@ -539,8 +548,9 @@ function action_change_password() * Redirect to the provider's auth URL * @param string $provider */ - function action_provider ($provider_name = null) + function action_provider () { + $provider_name = $this->request->param('provider'); if (Auth::instance()->logged_in()) { Message::add('success', 'Already logged in.'); @@ -564,13 +574,14 @@ function action_provider ($provider_name = null) return; } - function action_associate($provider_name = null) + function action_associate() { - if ($this->request->query('code') && $this->request->query('state')) - { - $this->action_associate_return($provider_name); - return; - } + $provider_name = $this->request->param('id'); + if ($this->request->query('code') && $this->request->query('state')) + { + $this->action_associate_return($provider_name); + return; + } if (Auth::instance()->logged_in()) { if (isset($_POST['confirmation']) && $_POST['confirmation'] == 'Y') @@ -624,8 +635,9 @@ function action_associate($provider_name = null) * prove that they want to trust that identity provider on your application. * */ - function action_associate_return($provider_name = null) + function action_associate_return() { + $provider_name = $this->request->param('id'); if (Auth::instance()->logged_in()) { $provider = Provider::factory($provider_name); @@ -668,8 +680,9 @@ function action_associate_return($provider_name = null) /** * Allow the user to login and register using a 3rd party provider. */ - function action_provider_return($provider_name = null) + function action_provider_return() { + $provider_name = $this->request->param('provider'); $provider = Provider::factory($provider_name); if (! is_object($provider)) { @@ -694,10 +707,13 @@ function action_provider_return($provider_name = null) // found, log user in Auth::instance()->force_login($user); // redirect to the user account - $this->request->redirect('user/profile'); + $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); return; } } + // If register is disabled, don't create new account + if(!Kohana::$config->load('useradmin.register_enabled')) + $this->request->redirect('user/login'); // create new account if (! Auth::instance()->logged_in()) { @@ -721,11 +737,7 @@ function action_provider_return($provider_name = null) try { // If the post data validates using the rules setup in the user model - $user->create_user($values, array( - 'username', - 'password', - 'email' - )); + $user->create_user($values, $this->user_model_fields); // Add the login role to the user (add a row to the db) $login_role = new Model_Role(array( 'name' => 'login' @@ -740,7 +752,7 @@ function action_provider_return($provider_name = null) // sign the user in Auth::instance()->login($values['username'], $password); // redirect to the user account - $this->request->redirect('user/profile'); + $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); } catch (ORM_Validation_Exception $e) { diff --git a/classes/useradmin/provider/facebook.php b/classes/useradmin/provider/facebook.php index e537361..e5e0b57 100644 --- a/classes/useradmin/provider/facebook.php +++ b/classes/useradmin/provider/facebook.php @@ -32,7 +32,7 @@ public function redirect_url($return_url) return $this->facebook->getLoginUrl(array( 'next' => URL::site($return_url, true), 'cancel_url' => URL::site($return_url, true), - 'req_perms' => 'email' + 'scope' => 'email' )); } @@ -42,7 +42,7 @@ public function redirect_url($return_url) */ public function verify() { - if ($this->facebook->getSession()) + if ($this->facebook->getUser()) { try { @@ -91,6 +91,11 @@ public function name() { return $this->me['first_name'] . ' ' . $this->me['last_name']; } + else if (isset($this->me['email'])) + { + $name = explode('@',$this->me['email']); + return $name[0]; + } return ''; } } \ No newline at end of file diff --git a/classes/useradmin/provider/twitter.php b/classes/useradmin/provider/twitter.php index ad7b005..f884979 100644 --- a/classes/useradmin/provider/twitter.php +++ b/classes/useradmin/provider/twitter.php @@ -21,10 +21,11 @@ public function __construct() */ public function verify() { + $config_secret = Kohana::$config->load('oauth')->get('twitter'); // create token $request_token = OAuth_Token::factory('request', array( - 'token' => Session::instance()->get('oauth_token'), - 'secret' => Session::instance()->get('oauth_token_secret') + 'token' => $_REQUEST['oauth_token'], + 'secret' => $config_secret['secret'] )); // Store the verifier in the token $request_token->verifier($_REQUEST['oauth_verifier']); diff --git a/views/template/useradmin.php b/views/template/useradmin.php index 895b222..cf645ae 100644 --- a/views/template/useradmin.php +++ b/views/template/useradmin.php @@ -13,17 +13,19 @@ diff --git a/views/user/login.php b/views/user/login.php index cd9a329..c5307cf 100644 --- a/views/user/login.php +++ b/views/user/login.php @@ -46,28 +46,35 @@ echo $form->close(); echo ' '; -echo ''; echo ''; ?> From a9e4d61dd502bb22ffd66d7a22069589874e10c4 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Fri, 15 Jun 2012 16:52:36 +0000 Subject: [PATCH 02/18] Following deeceefar2's lead, I'm removing the diff code from the sql file --- database/useradmin.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/database/useradmin.sql b/database/useradmin.sql index 593b822..e7f0eff 100644 --- a/database/useradmin.sql +++ b/database/useradmin.sql @@ -96,11 +96,7 @@ CREATE TABLE `user_tokens` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(11) unsigned NOT NULL, `user_agent` varchar(40) NOT NULL, -<<<<<<< HEAD - `token` varchar(40) NOT NULL, /* sha1 (which is Cookie:salt hashing method) hash - is 40 bytes long*/ -======= `token` varchar(40) NOT NULL, ->>>>>>> brennan87/develop `created` int(10) unsigned NOT NULL, `expires` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), From 1b2d40068aadc50b1d103ce8179f323f1382a3f0 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Mon, 18 Jun 2012 15:05:41 +0000 Subject: [PATCH 03/18] Appform helper - Changing private methods to protected in order to override --- classes/useradmin/appform.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/useradmin/appform.php b/classes/useradmin/appform.php index da7cbfd..4aa1efb 100644 --- a/classes/useradmin/appform.php +++ b/classes/useradmin/appform.php @@ -43,7 +43,7 @@ class Useradmin_Appform { * @param string $class * @return array */ - private static function add_class ($attributes, $class) + protected static function add_class ($attributes, $class) { if (isset($attributes['class'])) { @@ -62,7 +62,7 @@ private static function add_class ($attributes, $class) * @param $value * @param $attributes */ - private function load_values ($name, &$value, &$attributes) + protected function load_values ($name, &$value, &$attributes) { if (isset($this->errors[$name])) { @@ -85,7 +85,7 @@ private function load_values ($name, &$value, &$attributes) * @param string $attrInfo $attributes['info'] * @return string */ - private function addAlertSpan($errorName, $attributes = NULL) + protected function addAlertSpan($errorName, $attributes = NULL) { if (isset($errorName)) { From 9b0a06ab083cdb8e6cc9af6310c7235ee241a88f Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Mon, 18 Jun 2012 15:17:24 +0000 Subject: [PATCH 04/18] Adding required config setting to useradmin module config file --- config/useradmin.php | 1 + 1 file changed, 1 insertion(+) diff --git a/config/useradmin.php b/config/useradmin.php index 3525855..e6496dc 100644 --- a/config/useradmin.php +++ b/config/useradmin.php @@ -1,6 +1,7 @@ true, /** * The number of failed logins allowed can be specified here: * If the user mistypes their password X times, then they will not be permitted to log in during the jail time. From 0d4c2f8b3a00a1c104a945c176298efbfa90a0b7 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Mon, 18 Jun 2012 15:28:36 +0000 Subject: [PATCH 05/18] Taking Register link out of default template if registration is disabled --- views/template/default.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/views/template/default.php b/views/template/default.php index ab2e92d..5a3afae 100644 --- a/views/template/default.php +++ b/views/template/default.php @@ -13,17 +13,19 @@ From c812e0e98c83b2ebc08415e34e3c00473d2738f0 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Wed, 18 Jul 2012 14:28:37 -0500 Subject: [PATCH 06/18] Adding class property to allow easier overriding of default styles and scripts --- classes/useradmin/controller/app.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/classes/useradmin/controller/app.php b/classes/useradmin/controller/app.php index b1693aa..9d1797a 100644 --- a/classes/useradmin/controller/app.php +++ b/classes/useradmin/controller/app.php @@ -13,7 +13,13 @@ class Useradmin_Controller_App extends Controller { * @var string Filename of the template file. */ public $template = 'template/default'; - + + public $default_styles = array( + 'css/style.css' => 'screen' + ); + + public $default_scripts = array(); + /** * @var boolean Whether the template file should be rendered automatically. * @@ -150,10 +156,8 @@ public function after() { if ($this->auto_render === TRUE) { - $styles = array( - 'css/style.css' => 'screen' - ); - $scripts = array(); + $styles = $this->default_styles; + $scripts = $this->default_scripts; $this->template->styles = array_merge($this->template->styles, $styles); $this->template->scripts = array_merge($this->template->scripts, $scripts); From 560aae831ae084ed6f711b3e9f5a086ea58bbb08 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Wed, 12 Sep 2012 18:15:26 -0500 Subject: [PATCH 07/18] Redirect to / after logging in. I'm not sure if this is staying, but I'm commiting it for the moment. --- classes/useradmin/controller/user.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/classes/useradmin/controller/user.php b/classes/useradmin/controller/user.php index 15c9b50..015e406 100644 --- a/classes/useradmin/controller/user.php +++ b/classes/useradmin/controller/user.php @@ -191,7 +191,7 @@ public function action_register() if (Auth::instance()->logged_in() != false) { // redirect to the user account - $this->request->redirect('user/profile'); + $this->request->redirect('/'); } // Load the view $view = View::factory('user/register'); @@ -226,7 +226,7 @@ public function action_register() // sign the user in Auth::instance()->login($_POST['username'], $_POST['password']); // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Session::instance()->get_once('returnUrl','/')); } catch (ORM_Validation_Exception $e) { @@ -333,7 +333,7 @@ public function action_login() if (Auth::instance()->logged_in() != 0) { // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Session::instance()->get_once('returnUrl','/')); } $view = View::factory('user/login'); // If there is a post and $_POST is not empty @@ -344,7 +344,7 @@ public function action_login() Arr::get($_REQUEST,'remember',false)!=false) ){ // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Session::instance()->get_once('returnUrl','/')); return; } else @@ -381,7 +381,7 @@ public function action_logout() // Sign out the user Auth::instance()->logout(); // redirect to the user account and then the signin page if logout worked as expected - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Session::instance()->get_once('returnUrl','/')); } /** @@ -555,7 +555,7 @@ function action_provider () { Message::add('success', 'Already logged in.'); // redirect to the user account - $this->request->redirect('user/profile'); + $this->request->redirect('/'); } $provider = Provider::factory($provider_name); if ($this->request->query('code') && $this->request->query('state')) From 1959a2a72262e883093493f55d7d46ab17d413f0 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Mon, 15 Oct 2012 14:27:14 -0500 Subject: [PATCH 08/18] Force redirect back to URL user was attempting to access when session timed out. I'm not sure if the session is being cleared or what, but storing the return URL in the session was failing when logging in through a provider. Now it's stored in a cookie that overrides the session if set. --- classes/useradmin/controller/app.php | 1 + classes/useradmin/controller/user.php | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/classes/useradmin/controller/app.php b/classes/useradmin/controller/app.php index 9d1797a..f7aaf5e 100644 --- a/classes/useradmin/controller/app.php +++ b/classes/useradmin/controller/app.php @@ -68,6 +68,7 @@ public function access_required() */ public function login_required() { + Cookie::set('returnUrl', $_SERVER['REQUEST_URI']); Request::current()->redirect('user/login'); } diff --git a/classes/useradmin/controller/user.php b/classes/useradmin/controller/user.php index 015e406..4309a8e 100644 --- a/classes/useradmin/controller/user.php +++ b/classes/useradmin/controller/user.php @@ -49,6 +49,12 @@ class Useradmin_Controller_User extends Controller_App { 'password', 'email' ); + + /** Default Redirect URL + * The module defaults to the user's profile page, + * but this can be changed by overriding in your app. + */ + public $default_redirect_url = 'user/profile'; public function before(){ $baseUrl = Url::base(true); @@ -191,7 +197,7 @@ public function action_register() if (Auth::instance()->logged_in() != false) { // redirect to the user account - $this->request->redirect('/'); + $this->request->redirect($this->default_redirect_url); } // Load the view $view = View::factory('user/register'); @@ -226,7 +232,7 @@ public function action_register() // sign the user in Auth::instance()->login($_POST['username'], $_POST['password']); // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','/')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl',$this->default_redirect_url))); } catch (ORM_Validation_Exception $e) { @@ -288,7 +294,7 @@ public function action_unregister() ->execute(); // message: save success Message::add('success', __('User deleted.')); - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl','user/profile'))); } // display confirmation $this->template->content = View::factory('user/unregister') @@ -333,7 +339,7 @@ public function action_login() if (Auth::instance()->logged_in() != 0) { // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','/')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl',$this->default_redirect_url))); } $view = View::factory('user/login'); // If there is a post and $_POST is not empty @@ -344,7 +350,7 @@ public function action_login() Arr::get($_REQUEST,'remember',false)!=false) ){ // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','/')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl',$this->default_redirect_url))); return; } else @@ -381,7 +387,7 @@ public function action_logout() // Sign out the user Auth::instance()->logout(); // redirect to the user account and then the signin page if logout worked as expected - $this->request->redirect(Session::instance()->get_once('returnUrl','/')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl',$this->default_redirect_url))); } /** @@ -555,7 +561,7 @@ function action_provider () { Message::add('success', 'Already logged in.'); // redirect to the user account - $this->request->redirect('/'); + $this->request->redirect($this->default_redirect_url); } $provider = Provider::factory($provider_name); if ($this->request->query('code') && $this->request->query('state')) @@ -707,7 +713,7 @@ function action_provider_return() // found, log user in Auth::instance()->force_login($user); // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl','user/profile'))); return; } } @@ -752,7 +758,7 @@ function action_provider_return() // sign the user in Auth::instance()->login($values['username'], $password); // redirect to the user account - $this->request->redirect(Session::instance()->get_once('returnUrl','user/profile')); + $this->request->redirect(Cookie::get('returnUrl', Session::instance()->get_once('returnUrl','user/profile'))); } catch (ORM_Validation_Exception $e) { From 7cbff33fc2a6d66a7b192d0bb1e161d2cbce603f Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Tue, 23 Oct 2012 16:01:35 -0500 Subject: [PATCH 09/18] Make datatable output use initial request instead of current --- classes/useradmin/helper/datatable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/useradmin/helper/datatable.php b/classes/useradmin/helper/datatable.php index 1bf38c4..87fa52b 100644 --- a/classes/useradmin/helper/datatable.php +++ b/classes/useradmin/helper/datatable.php @@ -140,7 +140,7 @@ function render($params = null) if (( $name == $sort && $dir == 'DESC' ) || $name != $sort) { $result .= '' - . Html::anchor(URL::site(Request::current()->uri(), true) . URL::query(array( + . Html::anchor(URL::site(Request::initial()->uri(), true) . URL::query(array( 'page' => $page, 'sort' => $name, 'dir' => null @@ -152,7 +152,7 @@ function render($params = null) else { $result .= '' - . Html::anchor(URL::site(Request::current()->uri(), true) . URL::query(array( + . Html::anchor(URL::site(Request::initial()->uri(), true) . URL::query(array( 'page' => $page, 'sort' => $name, 'dir' => 'DESC' From d191ec9b08a7fe1f59a0c7f75841678fb65bb64f Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Thu, 13 Dec 2012 13:53:47 -0600 Subject: [PATCH 10/18] Making properties protected so they may be accessible in subclasses --- classes/useradmin/provider/facebook.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/useradmin/provider/facebook.php b/classes/useradmin/provider/facebook.php index e5e0b57..ca02432 100644 --- a/classes/useradmin/provider/facebook.php +++ b/classes/useradmin/provider/facebook.php @@ -6,11 +6,11 @@ */ class Useradmin_Provider_Facebook extends Provider { - private $facebook = null; + protected $facebook = null; - private $me = null; + protected $me = null; - private $uid = null; + protected $uid = null; public function __construct() { From 2664308d53949f8b325b54c1d4a2aa5588b922d4 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Wed, 16 Jan 2013 19:53:23 -0600 Subject: [PATCH 11/18] Correctly output error message when cannot save user on password reset instead of throwing an exception --- classes/useradmin/controller/user.php | 58 ++++++++++++++------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/classes/useradmin/controller/user.php b/classes/useradmin/controller/user.php index 4309a8e..6072beb 100644 --- a/classes/useradmin/controller/user.php +++ b/classes/useradmin/controller/user.php @@ -411,33 +411,37 @@ public function action_forgot() { // send an email with the account reset token $user->reset_token = $user->generate_password(32); - $user->save(); - $message = "You have requested a password reset. You can reset password to your account by visiting the page at:\n\n" . - ":reset_token_link\n\n" . - "If the above link is not clickable, please visit the following page:\n" . - ":reset_link\n\n" . - "and copy/paste the following Reset Token: :reset_token\nYour user account name is: :username\n"; - $mailer = Email::connect(); - // Create complex Swift_Message object stored in $message - // MUST PASS ALL PARAMS AS REFS - $subject = __('Account password reset'); - $to = $_POST['reset_email']; - $from = Kohana::$config->load('useradmin')->email_address; - $body = __($message, array( - ':reset_token_link' => URL::site('user/reset?reset_token='.$user->reset_token.'&reset_email='.$_POST['reset_email'], TRUE), - ':reset_link' => URL::site('user/reset', TRUE), - ':reset_token' => $user->reset_token, - ':username' => $user->username - )); - // FIXME: Test if Swift_Message has been found. - $message_swift = Swift_Message::newInstance($subject, $body)->setFrom($from)->setTo($to); - if ($mailer->send($message_swift)) - { - Message::add('success', __('Password reset email sent.')); - $this->request->redirect('user/login'); - } - else - { + try { + $user->save(); + $message = "You have requested a password reset. You can reset password to your account by visiting the page at:\n\n" . + ":reset_token_link\n\n" . + "If the above link is not clickable, please visit the following page:\n" . + ":reset_link\n\n" . + "and copy/paste the following Reset Token: :reset_token\nYour user account name is: :username\n"; + $mailer = Email::connect(); + // Create complex Swift_Message object stored in $message + // MUST PASS ALL PARAMS AS REFS + $subject = __('Account password reset'); + $to = $_POST['reset_email']; + $from = Kohana::$config->load('useradmin')->email_address; + $body = __($message, array( + ':reset_token_link' => URL::site('user/reset?reset_token='.$user->reset_token.'&reset_email='.$_POST['reset_email'], TRUE), + ':reset_link' => URL::site('user/reset', TRUE), + ':reset_token' => $user->reset_token, + ':username' => $user->username + )); + // FIXME: Test if Swift_Message has been found. + $message_swift = Swift_Message::newInstance($subject, $body)->setFrom($from)->setTo($to); + if ($mailer->send($message_swift)) + { + Message::add('success', __('Password reset email sent.')); + $this->request->redirect('user/login'); + } + else + { + Message::add('failure', __('Could not send email.')); + } + } catch(Exception $e) { Message::add('failure', __('Could not send email.')); } } From 83549d2c4239097d633f08c092399c3f9829cd74 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Wed, 16 Jan 2013 20:31:29 -0600 Subject: [PATCH 12/18] Adding a method to turn off validation for saving the user when resetting the password. Otherwise, if new rules have been added, users that do not satisfy the rules cannot reset their passwords. --- classes/useradmin/controller/user.php | 1 + classes/useradmin/model/user.php | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/classes/useradmin/controller/user.php b/classes/useradmin/controller/user.php index 6072beb..752500a 100644 --- a/classes/useradmin/controller/user.php +++ b/classes/useradmin/controller/user.php @@ -411,6 +411,7 @@ public function action_forgot() { // send an email with the account reset token $user->reset_token = $user->generate_password(32); + $user->validation_required(false); try { $user->save(); $message = "You have requested a password reset. You can reset password to your account by visiting the page at:\n\n" . diff --git a/classes/useradmin/model/user.php b/classes/useradmin/model/user.php index 0221599..8995dfc 100644 --- a/classes/useradmin/model/user.php +++ b/classes/useradmin/model/user.php @@ -26,6 +26,8 @@ class Useradmin_Model_User extends Model_Auth_User { protected $_updated_column = array('column' => 'modified', 'format' => 'Y-m-d H:i:s'); + protected $_validation_required = TRUE; + /** * Rules for the user model. Because the password is _always_ a hash * when it's set,you need to run an additional not_empty rule in your controller @@ -37,12 +39,28 @@ class Useradmin_Model_User extends Model_Auth_User { */ public function rules() { - $parent = parent::rules(); - // fixes the min_length username value - $parent['username'][1] = array('min_length', array(':value', 1)); - return $parent; + if ($this->validation_required()) + { + $parent = parent::rules(); + // fixes the min_length username value + $parent['username'][1] = array('min_length', array(':value', 1)); + return $parent; + } + return array(); } + public function validation_required($required = null) + { + if ($required === NULL) + { + // work as getter + return $this->_validation_required; + } + // set value + $this->_validation_required = (bool)$required; + return $this; + } + // TODO overload filters() and add username/created_on/updated_on coluns filters /** From 50e697814ecae12d065257817a3eff19744247f8 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Tue, 22 Jan 2013 16:58:04 -0600 Subject: [PATCH 13/18] Making private properties protected for access from subclass --- classes/useradmin/provider/twitter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/useradmin/provider/twitter.php b/classes/useradmin/provider/twitter.php index f884979..3ff667f 100644 --- a/classes/useradmin/provider/twitter.php +++ b/classes/useradmin/provider/twitter.php @@ -6,9 +6,9 @@ class Useradmin_Provider_Twitter extends Provider_OAuth { * Data storage * @var int */ - private $uid = null; + protected $uid = null; - private $data = null; + protected $data = null; public function __construct() { From 0a104baf24e01657004ad2ab85edbc09b9f6b57e Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Tue, 5 Mar 2013 15:20:07 -0600 Subject: [PATCH 14/18] Facebook module: Making private properties protected for use in child classes --- classes/useradmin/provider/facebook.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/useradmin/provider/facebook.php b/classes/useradmin/provider/facebook.php index e5e0b57..ca02432 100644 --- a/classes/useradmin/provider/facebook.php +++ b/classes/useradmin/provider/facebook.php @@ -6,11 +6,11 @@ */ class Useradmin_Provider_Facebook extends Provider { - private $facebook = null; + protected $facebook = null; - private $me = null; + protected $me = null; - private $uid = null; + protected $uid = null; public function __construct() { From 1ef851efd1c948813488d9e94f58c8503063a2dc Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Thu, 11 Apr 2013 12:05:20 -0500 Subject: [PATCH 15/18] Turn off validation during user login. If validation rules are added for registration/profile editing, login failed for any users not matching those rules. --- classes/useradmin/auth/orm.php | 2 ++ classes/useradmin/model/user.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/classes/useradmin/auth/orm.php b/classes/useradmin/auth/orm.php index d6f3913..62ddda6 100644 --- a/classes/useradmin/auth/orm.php +++ b/classes/useradmin/auth/orm.php @@ -30,6 +30,8 @@ protected function _login($user, $password, $remember) // Load the user $user = ORM::factory('user'); $user->where($user->unique_key($username), '=', $username)->find(); + if($user->loaded()) + $user->validation_required(false); } // if there are too many recent failed logins, fail now diff --git a/classes/useradmin/model/user.php b/classes/useradmin/model/user.php index 8995dfc..894438b 100644 --- a/classes/useradmin/model/user.php +++ b/classes/useradmin/model/user.php @@ -39,7 +39,7 @@ class Useradmin_Model_User extends Model_Auth_User { */ public function rules() { - if ($this->validation_required()) + if ($this->_validation_required) { $parent = parent::rules(); // fixes the min_length username value From 76173e8a15e6fe2f5207149748bb1c4e1303f6ab Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Mon, 15 Apr 2013 10:01:30 -0500 Subject: [PATCH 16/18] Allow resetting password even if user wouldn't pass validation --- classes/useradmin/controller/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/classes/useradmin/controller/user.php b/classes/useradmin/controller/user.php index 752500a..5634017 100644 --- a/classes/useradmin/controller/user.php +++ b/classes/useradmin/controller/user.php @@ -493,6 +493,7 @@ function action_reset() $user->password = $password; // This field does not exist in the default config: // $user->failed_login_count = 0; + $user->validation_required(false); $user->save(); Message::add('success', __('Password reset.')); Message::add('success', '

' From 34df3de97eb00d29ff7b6ccd35a3035cd24b671c Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Mon, 15 Apr 2013 13:48:35 -0500 Subject: [PATCH 17/18] Turn off validation for login function which updates login count and last login time --- classes/useradmin/model/user.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/classes/useradmin/model/user.php b/classes/useradmin/model/user.php index 894438b..7f11036 100644 --- a/classes/useradmin/model/user.php +++ b/classes/useradmin/model/user.php @@ -61,6 +61,28 @@ public function validation_required($required = null) return $this; } + /** + * Complete the login for a user by incrementing the logins and saving login timestamp + * + * @return void + */ + public function complete_login() + { + if ($this->_loaded) + { + // Update the number of logins + $this->logins = new Database_Expression('logins + 1'); + + // Set the last login date + $this->last_login = time(); + + $this->validation_required(false); + + // Save the user + $this->update(); + } + } + // TODO overload filters() and add username/created_on/updated_on coluns filters /** From 9c6d8a85043910ea14205ffaccf36784fa96af02 Mon Sep 17 00:00:00 2001 From: Eric Blount Date: Wed, 12 Jun 2013 16:18:18 -0500 Subject: [PATCH 18/18] Switching to new version of Twitter API for login --- classes/useradmin/provider/twitter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/useradmin/provider/twitter.php b/classes/useradmin/provider/twitter.php index 3ff667f..133ed47 100644 --- a/classes/useradmin/provider/twitter.php +++ b/classes/useradmin/provider/twitter.php @@ -34,7 +34,7 @@ public function verify() if ($access_token and $access_token->name === 'access') { // @link http://dev.twitter.com/doc/get/account/verify_credentials - $request = OAuth_Request::factory('resource', 'GET', 'http://api.twitter.com/1/account/verify_credentials.json', array( + $request = OAuth_Request::factory('resource', 'GET', 'http://api.twitter.com/1.1/account/verify_credentials.json', array( 'oauth_consumer_key' => $this->consumer->key, 'oauth_token' => $access_token->token ));