From 9cc2a6602b47ac97d72efa51ec654418b252b4e4 Mon Sep 17 00:00:00 2001 From: Calin Burloiu Date: Mon, 26 Sep 2011 18:47:09 +0300 Subject: [PATCH] account activation and password recovery implemented --- application/config/form_validation.php | 16 +- application/config/p2p-tube.php | 13 +- application/controllers/message.php | 54 +++++ application/controllers/user.php | 185 +++++++++++++++--- .../exceptions/Send_email_exception.php | 6 + .../language/english/form_validation_lang.php | 6 + application/language/english/user_lang.php | 32 +++ application/libraries/Image.php | 90 +++++++++ application/models/users_model.php | 85 +++++++- application/views/message/error_view.php | 6 + application/views/message/info_view.php | 6 + application/views/user/login_view.php | 6 + .../views/user/recover_password_view.php | 36 ++++ application/views/user/register_view.php | 10 +- css/default.css | 5 + 15 files changed, 520 insertions(+), 36 deletions(-) create mode 100644 application/controllers/message.php create mode 100644 application/exceptions/Send_email_exception.php create mode 100644 application/libraries/Image.php create mode 100644 application/views/message/error_view.php create mode 100644 application/views/message/info_view.php create mode 100644 application/views/user/recover_password_view.php diff --git a/application/config/form_validation.php b/application/config/form_validation.php index 55e0212..ff6bd0d 100644 --- a/application/config/form_validation.php +++ b/application/config/form_validation.php @@ -1,7 +1,7 @@ array( + 'login'=> array( array( 'field'=>'username', 'label'=>'lang:user_username_or_email', @@ -86,6 +86,20 @@ $config = array( 'label'=>'lang:user_email', 'rules'=>'trim|required|xss_clean|valid_email|callback__do_resend_activation' ) + ), + 'recover_password'=> array( + array( + 'field'=>'username', + 'label'=>'lang:user_username', + 'rules'=>'trim|required|min_length[5]|max_length[32]' + . '|strtolower|callback__valid_username|callback__username_exists|callback__internal_account' + . '|callback__do_recover_password' + ), + array( + 'field'=>'email', + 'label'=>'lang:user_email', + 'rules'=>'trim|required|xss_clean|valid_email' + ) ) ); diff --git a/application/config/p2p-tube.php b/application/config/p2p-tube.php index 85dc44a..e924e69 100644 --- a/application/config/p2p-tube.php +++ b/application/config/p2p-tube.php @@ -134,4 +134,15 @@ $config['search_results_per_page'] = 20; $config['available_languages_list'] = array( 'en'=>'english', 'ro'=>'romanian' -); \ No newline at end of file +); + +/* +|-------------------------------------------------------------------------- +| No-Reply E-mail address +|-------------------------------------------------------------------------- +| +| The e-mail address from which the users receive e-mail notifications +| like account activation e-mail or password recovery. +| +*/ +$config['noreply_email'] = 'no-reply@p2p-next.cs.pub.ro'; \ No newline at end of file diff --git a/application/controllers/message.php b/application/controllers/message.php new file mode 100644 index 0000000..5d8b9dc --- /dev/null +++ b/application/controllers/message.php @@ -0,0 +1,54 @@ +msg = $this->session->flashdata('msg'); + } + + public function _remap($method, $params = array()) + { + if (! $this->msg) + header('Location: '. site_url()); + + $params = array( + 'title'=> $this->lang->line("message_title_{$method}") + .' – ' + . $this->config->item('site_name'), + //'metas' => array('description'=>'') + ); + $this->load->library('html_head_params', $params); + + // ** + // ** LOADING VIEWS + // ** + $this->load->view('html_begin', $this->html_head_params); + $this->load->view('header', array()); + + $main_params['content'] = + $this->load->view("message/{$method}_view", + array('msg'=> $this->msg), TRUE); + + $main_params['side'] = $this->load->view('side_default', NULL, TRUE); + $this->load->view('main', $main_params); + + $this->load->view('footer'); + $this->load->view('html_end'); + } +} + +/* End of file message.php */ +/* Location: ./application/controllers/message.php */ diff --git a/application/controllers/user.php b/application/controllers/user.php index 8c43cce..96454be 100644 --- a/application/controllers/user.php +++ b/application/controllers/user.php @@ -23,6 +23,11 @@ class User extends CI_Controller { public function index() { } + + public function test($user_id = 1) + { + echo sha1('hQwCUEPQZcN8c4Es'); + } /** * Login a user and then redirect it to the last page which must be encoded @@ -38,7 +43,7 @@ class User extends CI_Controller { $this->form_validation->set_error_delimiters('', ''); - if ($this->form_validation->run('signin') === FALSE) + if ($this->form_validation->run('login') === FALSE) { $params = array( 'title' => $this->lang->line('ui_nav_menu_login') @@ -273,29 +278,60 @@ class User extends CI_Controller { public function activate($user_id, $method='', $activation_code='') { - $user_id = intval($user_id); + $user_id = intval($user_id); + $res_form_validation = FALSE; + + if ($method == 'code') + { + if (! $activation_code) + $res_form_validation = $this->form_validation->run('activate'); + // Activation code is provided in URL. + else + { + if ($this->_valid_activation_code($activation_code) + && $this->users_model->activate_account($user_id, + $activation_code)) + { + $this->session->set_flashdata('msg', sprintf( + $this->lang->line('user_msg_activated_account'), + site_url('user/login'))); + header('Location: '. site_url('message/info')); + return; + } + else + { + $this->session->set_flashdata('msg', + $this->lang->line('user_msg_wrong_activation_code')); + header('Location: '. site_url('message/error')); + return; + } + } + } + else if ($method == 'resend') + { + $res_form_validation = + $this->form_validation->run('resend_activation'); + } + $userdata = $this->users_model->get_userdata($user_id, 'email, a.activation_code'); $email = $userdata['email']; - //print_r($userdata['activation_code']); $activated_account = ($userdata['activation_code'] == NULL); + if ($activated_account) + { + $this->session->set_flashdata('msg', sprintf( + $this->lang->line('user_msg_activated_account'), + site_url('user/login'))); + header('Location: '. site_url('message/info')); + return; + } + $this->load->library('form_validation'); $this->form_validation->set_error_delimiters('', ''); - $res_form_validation = FALSE; - if ($method == 'code') - { - $res_form_validation = $this->form_validation->run('activate'); - } - else if ($method == 'resend') - { - $res_form_validation = - $this->form_validation->run('resend_activation'); - } - if ($res_form_validation === FALSE) { $params = array( @@ -312,19 +348,12 @@ class User extends CI_Controller { $this->load->view('html_begin', $this->html_head_params); $this->load->view('header', array()); - if (! $activated_account) - { - $main_params['content'] = - $this->load->view('user/activate_view', - array('user_id'=> $user_id, 'email'=> $userdata['email']), - TRUE); - } - else - { - $main_params['content'] = - $this->load->view('user/activated_account_view', - NULL, TRUE); - } + // Show form + $main_params['content'] = + $this->load->view('user/activate_view', + array( 'user_id'=> $user_id, + 'email'=> $userdata['email']), + TRUE); $main_params['side'] = $this->load->view('side_default', NULL, TRUE); $this->load->view('main', $main_params); @@ -338,16 +367,71 @@ class User extends CI_Controller { { // Redirect to a message which tells the user that the // activation was successful. - header('Location: '. site_url("user/activate/$user_id")); + $this->session->set_flashdata('msg', sprintf( + $this->lang->line('user_msg_activated_account'), + site_url('user/login'))); + header('Location: '. site_url('message/info')); + return; } else if ($method == 'resend') { - // Redirect to home page - header('Location: '. site_url()); + // Redirect to resent message + $this->session->set_flashdata('msg', sprintf( + $this->lang->line('user_msg_activation_resent'), + $this->input->post('email'))); + header('Location: '. site_url('message/info')); + return; } } } + public function recover_password() + { + $this->load->library('form_validation'); + + $this->form_validation->set_error_delimiters('', + ''); + + if ($this->form_validation->run('recover_password') === FALSE) + { + $params = array( 'title' => + $this->lang->line( + 'user_title_password_recovery') + .' – ' + . $this->config->item('site_name'), + //'metas' => array('description'=>'') + ); + $this->load->library('html_head_params', $params); + + // ** + // ** LOADING VIEWS + // ** + $this->load->view('html_begin', $this->html_head_params); + $this->load->view('header', array('selected_menu' => + 'recover_password')); + + $main_params['content'] = $this->load->view( + 'user/recover_password_view', array(), + TRUE); + + $main_params['side'] = $this->load->view('side_default', NULL, TRUE); + $this->load->view('main', $main_params); + + $this->load->view('footer'); + $this->load->view('html_end'); + } + else + { + // Redirect to resent message + $this->session->set_flashdata('msg', sprintf( + $this->lang->line('user_msg_password_recovery_email_sent'), + $this->input->post('username'), + $this->input->post('email'))); + header('Location: '. site_url('message/info')); + return; + } + } + public function _update_session_userdata($data) { foreach ($data as $key=> $val) @@ -457,7 +541,46 @@ class User extends CI_Controller { public function _do_resend_activation($email) { - return FALSE; + $user_id = $this->input->post('user-id'); + if ($user_id === FALSE) + return FALSE; + $user_id = intval($user_id); + + $this->users_model->set_userdata($user_id, + array('email'=> $email)); + + return $this->users_model->send_activation_email($user_id, $email); + } + + public function _username_exists($username) + { + $userdata = $this->users_model->get_userdata($username); + + if (! $userdata) + return FALSE; + + return TRUE; + } + + public function _internal_account($username) + { + $userdata = $this->users_model->get_userdata($username, 'auth_src'); + if (! $userdata) + return FALSE; + + if ($userdata['auth_src'] != 'internal') + return FALSE; + + return TRUE; + } + + public function _do_recover_password($username) + { + $email = $this->input->post('email'); + if (! $email) + return FALSE; + + return $this->users_model->recover_password($username, $email); } } diff --git a/application/exceptions/Send_email_exception.php b/application/exceptions/Send_email_exception.php new file mode 100644 index 0000000..17b3009 --- /dev/null +++ b/application/exceptions/Send_email_exception.php @@ -0,0 +1,6 @@ +activation e-mail on your e-mail address you provided. In order to confirm that you are the owner of that e-mail address, follow the link there or enter the activation code also provided in that e-mail in the field below.'; $lang['user_activation_code'] = 'Activation Code'; $lang['user_submit_activate'] = 'Activate Account'; +$lang['user_submit_password_recovery'] = 'Recover Password'; $lang['user_legend_resend_activation'] = 'Resend the activation code'; $lang['user_instruction_resend_activation'] = 'The activation e-mail can take up to a few minutes until it arrives in your inbox, so please be patient. If you entered a wrong e-mail address, you can change it by entering another one in the field below. Pressing Resend will cause us to retransmit you the activation e-mail on the address entered in this field.'; +$lang['user_instruction_password_recovery'] = 'Enter you username and the e-mail address associated with your account and we will send you a new auto-generated password.'; $lang['user_submit_resend_activation'] = 'Resend Activation E-mail'; $lang['user_msg_activated_account'] = 'Your account is active so you can login. You successfully validated your e-mail address through the activation e-mail.'; +$lang['user_msg_wrong_activation_code'] = 'Wrong account activation code!'; +$lang['user_msg_activation_resent'] = 'Activation e-mail has been resent to %s!'; +$lang['user_msg_password_recovery_email_sent'] = 'An e-mail with a new password for user %s has been sent to %s.'; +$lang['user_link_password_recovery'] = 'Did you forget your password?'; +$lang['user_activation_email_content'] = +"Hello %s, + +Please confirm that you registered a new account on %s (%s) by following the link below: + +%s + +If the link does not work try to copy it and then paste it into your address bar. + +Alternatively you can use the following Activation Code: %s + +Thank for registering! +"; +$lang['user_password_recovery_email_content'] = +"Hello %s, + +You requested a password recovery on %s (%s). Here is your new auto-generated password: + +%s + +It is recommended to change this password after you log in. + +Best regards! +"; $lang['user_no_videos_uploaded'] = 'The user uploaded no videos.'; diff --git a/application/libraries/Image.php b/application/libraries/Image.php new file mode 100644 index 0000000..c4cd5fe --- /dev/null +++ b/application/libraries/Image.php @@ -0,0 +1,90 @@ +image_type = $image_info[2]; + if( $this->image_type == IMAGETYPE_JPEG ) { + $this->image = imagecreatefromjpeg($filename); + } elseif( $this->image_type == IMAGETYPE_GIF ) { + $this->image = imagecreatefromgif($filename); + } elseif( $this->image_type == IMAGETYPE_PNG ) { + $this->image = imagecreatefrompng($filename); + } + } + function save($filename, $image_type=IMAGETYPE_JPEG, $compression=60, $permissions=null) { + if( $image_type == IMAGETYPE_JPEG ) { + imagejpeg($this->image,$filename,$compression); + } elseif( $image_type == IMAGETYPE_GIF ) { + imagegif($this->image,$filename); + } elseif( $image_type == IMAGETYPE_PNG ) { + imagepng($this->image,$filename); + } + if( $permissions != null) { + chmod($filename,$permissions); + } + } + function output($image_type=IMAGETYPE_JPEG) { + if( $image_type == IMAGETYPE_JPEG ) { + imagejpeg($this->image); + } elseif( $image_type == IMAGETYPE_GIF ) { + imagegif($this->image); + } elseif( $image_type == IMAGETYPE_PNG ) { + imagepng($this->image); + } + } + function saveThumbnail($filename, $width, $height) + { + $ratio = $this->getWidth() / $this->getHeight(); + $thumbRatio = $width / $height; + + if($ratio < $thumbRatio) + $this->resizeToHeight($height); + else + $this->resizeToWidth($width); + + $this->save($filename); + } + function getWidth() { + return imagesx($this->image); + } + function getHeight() { + return imagesy($this->image); + } + function resizeToHeight($height) { + $ratio = $height / $this->getHeight(); + $width = $this->getWidth() * $ratio; + $this->resize($width,$height); + } + function resizeToWidth($width) { + $ratio = $width / $this->getWidth(); + $height = $this->getheight() * $ratio; + $this->resize($width,$height); + } + function scale($scale) { + $width = $this->getWidth() * $scale/100; + $height = $this->getheight() * $scale/100; + $this->resize($width,$height); + } + function resize($width,$height) { + $new_image = imagecreatetruecolor($width, $height); + imagecopyresampled($new_image, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight()); + $this->image = $new_image; + } +} + + +/* End of file Singleton_db.php */ +/* Location: ./application/libraries/Singleton_db.php */ diff --git a/application/models/users_model.php b/application/models/users_model.php index 6faa6fa..d59987c 100644 --- a/application/models/users_model.php +++ b/application/models/users_model.php @@ -221,13 +221,15 @@ class Users_model extends CI_Model { if ($query === FALSE) return FALSE; - // If the registered with internal authentication it needs to activate + // If registered with internal authentication it needs to activate // the account. - $activation_code = Users_model::gen_activation_code(); + $activation_code = Users_model::gen_activation_code($data['username']); $user_id = $this->get_user_id($data['username']); $query = $this->db->query("INSERT INTO `users_unactivated` (user_id, activation_code) VALUES ($user_id, '$activation_code')"); + $this->send_activation_email($user_id, $data['email'], + $activation_code, $data['username']); // TODO exception on failure return $query; @@ -272,6 +274,64 @@ class Users_model extends CI_Model { return TRUE; } + public function send_activation_email($user_id, $email = NULL, + $activation_code = NULL, $username = NULL) + { + if (!$activation_code || !$email || !$username) + { + if (!$email) + $cols = 'email, '; + else + $cols = ''; + + $userdata = $this->get_userdata($user_id, + $cols. "a.activation_code, username"); + $activation_code =& $userdata['activation_code']; + + if (!$email) + $email =& $userdata['email']; + $username =& $userdata['username']; + } + + if ($activation_code === NULL) + return TRUE; + + $subject = '['. $this->config->item('site_name') + . '] Account Activation'; + $activation_url = + site_url("user/activate/$user_id/code/$activation_code"); + $msg = sprintf($this->lang->line('user_activation_email_content'), + $username, $this->config->item('site_name'), site_url(), + $activation_url, $activation_code); + $headers = "From: ". $this->config->item('noreply_email'); + + return mail($email, $subject, $msg, $headers); + } + + public function recover_password($username, $email) + { + $userdata = $this->get_userdata($username, 'email, username, id'); + + if (strcmp($userdata['email'], $email) !== 0) + return FALSE; + + $recovered_password = Users_model::gen_password(); + + $this->set_userdata(intval($userdata['id']), array('password'=> + $recovered_password)); + + $subject = '['. $this->config->item('site_name') + . '] Password Recovery'; + $msg = sprintf($this->lang->line('user_password_recovery_email_content'), + $username, $this->config->item('site_name'), site_url(), + $recovered_password); + $headers = "From: ". $this->config->item('noreply_email'); + + mail($email, $subject, $msg, $headers); + + return TRUE; + } + /** * Returns data from `users` table. If $user is int it is used as an * id, if it is string it is used as an username. @@ -307,6 +367,7 @@ class Users_model extends CI_Model { * @param int $user_id * @param array $data key-value pairs with columns and new values to be * modified + * @return boolean returns TRUE on success and FALSE otherwise */ public function set_userdata($user_id, $data) { @@ -349,6 +410,26 @@ class Users_model extends CI_Model { return $activation_code; } + public static function gen_password() + { + $ci =& get_instance(); + $length = 16; + $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.?!_-'; + $len_chars = strlen($chars); + $enc_key = $ci->config->item('encryption_key'); + $len_enc_key = strlen($enc_key); + $password = ''; + + for ($p = 0; $p < $length; $p++) + { + $i = (mt_rand(1, 100) * ord($enc_key[ mt_rand(0, $len_enc_key-1) ])) + % $len_chars; + $password .= $chars[$i]; + } + + return $password; + } + public static function roles_to_string($roles) { $ci =& get_instance(); diff --git a/application/views/message/error_view.php b/application/views/message/error_view.php new file mode 100644 index 0000000..d7dace7 --- /dev/null +++ b/application/views/message/error_view.php @@ -0,0 +1,6 @@ +
+
+

+

+
+
\ No newline at end of file diff --git a/application/views/message/info_view.php b/application/views/message/info_view.php new file mode 100644 index 0000000..82282fb --- /dev/null +++ b/application/views/message/info_view.php @@ -0,0 +1,6 @@ +
+
+

+

+
+
\ No newline at end of file diff --git a/application/views/user/login_view.php b/application/views/user/login_view.php index 2a3f945..b066866 100644 --- a/application/views/user/login_view.php +++ b/application/views/user/login_view.php @@ -26,5 +26,11 @@ + + + +

lang->line('user_link_password_recovery') ?>

+ + \ No newline at end of file diff --git a/application/views/user/recover_password_view.php b/application/views/user/recover_password_view.php new file mode 100644 index 0000000..954587c --- /dev/null +++ b/application/views/user/recover_password_view.php @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

lang->line('user_instruction_password_recovery'); ?>

+
lang->line('user_username'). ': ' ?> + +
lang->line('user_email'). ': ' ?> + +
+ +
+ \ No newline at end of file diff --git a/application/views/user/register_view.php b/application/views/user/register_view.php index 42159c2..438c410 100644 --- a/application/views/user/register_view.php +++ b/application/views/user/register_view.php @@ -41,7 +41,7 @@ endif; - lang->line('user_username'). ': ' ?> + lang->line('user_username'). ' : ' ?>   ` @@ -143,6 +143,14 @@ endif; + + lang->line('user_picture'). ' : ' ?> + + + + + +   diff --git a/css/default.css b/css/default.css index 4448c97..223ef1c 100644 --- a/css/default.css +++ b/css/default.css @@ -20,6 +20,11 @@ a:hover, a:active text-decoration: underline; } +.ui-state-highlight a +{ + color: rgb(0,90,192) !important; +} + h1 { margin-top: 8px; -- 2.20.1