From: Calin Burloiu Date: Thu, 22 Sep 2011 16:30:49 +0000 (+0300) Subject: user profile page; account activation backend (without UI) X-Git-Url: http://p2p-next.cs.pub.ro/gitweb/?p=living-lab-site.git;a=commitdiff_plain;h=37fe2e29a60066614f4155c292e2a2bd99b71b49 user profile page; account activation backend (without UI) --- diff --git a/application/config/constants.php b/application/config/constants.php index 4a879d3..6456597 100644 --- a/application/config/constants.php +++ b/application/config/constants.php @@ -26,7 +26,6 @@ define('DIR_WRITE_MODE', 0777); | These modes are used when working with fopen()/popen() | */ - define('FOPEN_READ', 'rb'); define('FOPEN_READ_WRITE', 'r+b'); define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care @@ -36,6 +35,16 @@ define('FOPEN_READ_WRITE_CREATE', 'a+b'); define('FOPEN_WRITE_CREATE_STRICT', 'xb'); define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b'); +/* +|-------------------------------------------------------------------------- +| User Roles +|-------------------------------------------------------------------------- +| +| Define bits significance in user roles bit mask. +| +*/ +define('USER_ROLE_STANDARD', 0); +define('USER_ROLE_ADMIN', 1); /* End of file constants.php */ /* Location: ./application/config/constants.php */ \ No newline at end of file diff --git a/application/controllers/catalog.php b/application/controllers/catalog.php index 4570c1e..8e69a64 100644 --- a/application/controllers/catalog.php +++ b/application/controllers/catalog.php @@ -26,20 +26,21 @@ class Catalog extends CI_Controller { { // Videos $vs_data['videos'] = $this->videos_model->get_videos_summary( - $id, 0, $this->config->item('videos_per_row')); + $id, NULL, 0, $this->config->item('videos_per_row')); // Category $vs_data['category_name'] = $name; - $vs_data['category_title'] = $name ? - $this->lang->line("ui_categ_$name") : $name; $vs_data['category_id'] = $id; + $videos_summary['category_name'] = $name; + $videos_summary['category_title'] = $name ? + $this->lang->line("ui_categ_$name") : $name; // Pagination (not required) $vs_data['pagination'] = ''; - $data['videos_summaries'][] = - $this->load->view('catalog/videos_summary_view', - $vs_data, TRUE); + $videos_summary['content'] = $this->load->view( + 'catalog/videos_summary_view', $vs_data, TRUE); + $data['videos_summaries'][] = $videos_summary; } $params = array( 'title' => $this->config->item('site_name'), @@ -69,7 +70,8 @@ class Catalog extends CI_Controller { public function test($page = 0) { - echo $this->uri->segment(1); + $this->load->model('users_model'); + echo Users_model::gen_activation_code('calin.burloiu'); } public function category($category_name, $ordering = 'hottest', $offset = 0) @@ -78,12 +80,12 @@ class Catalog extends CI_Controller { // ** LOADING MODEL // ** // Video Category - $vs_data = $this->_get_category_data($category_name); + $category_data = Catalog::_get_category_data($category_name); // Retrieve videos summary. $this->load->model('videos_model'); $vs_data['videos'] = $this->videos_model->get_videos_summary( - $vs_data['category_id'], intval($offset), + $category_data['category_id'], NULL, intval($offset), $this->config->item('videos_per_page'), $ordering); $vs_data['ordering'] = $ordering; @@ -93,22 +95,19 @@ class Catalog extends CI_Controller { $pg_config['base_url'] = site_url("catalog/category/$category_name/$ordering/"); $pg_config['uri_segment'] = 5; $pg_config['total_rows'] = $this->videos_model->get_videos_count( - $vs_data['category_id']); + $category_data['category_id']); $pg_config['per_page'] = $this->config->item('videos_per_page'); $this->pagination->initialize($pg_config); $vs_data['pagination'] = $this->pagination->create_links(); - - // Video Summary -// $data['video_summary'] = $this->load->view('catalog/videos_summary_view', -// $vs_data, TRUE); + $vs_data['category_name'] = $category_data['category_name']; + $vs_data['title'] = $category_data['category_title']; $params = array( 'title' => - $vs_data['category_title'].' – ' + $category_data['category_title'].' – ' . $this->config->item('site_name'), 'css' => array( 'catalog.css' - ), - //'js' => array(), + ) //'metas' => array('description'=>'','keywords'=>'') ); $this->load->library('html_head_params', $params); @@ -121,7 +120,6 @@ class Catalog extends CI_Controller { 'search_category_name'=> $vs_data['category_name'] )); -// $main_params['content'] = $this->load->view('catalog/category_view', $data, TRUE); $main_params['content'] = $this->load->view('catalog/videos_summary_view', $vs_data, TRUE); $main_params['side'] = $this->load->view('side_default', NULL, TRUE); @@ -161,7 +159,7 @@ class Catalog extends CI_Controller { $results_data['search_query'] = $search_query; // Category - $results_data = $this->_get_category_data($category_name); + $results_data = Catalog::_get_category_data($category_name); if ($results_data === NULL) $results_data = array('category_id'=>NULL); @@ -255,17 +253,19 @@ class Catalog extends CI_Controller { $this->load->view('html_end'); } - public function _get_category_data($category_name) + public static function _get_category_data($category_name) { + $ci =& get_instance(); + if ($category_name === NULL) return NULL; - $categories = $this->config->item('categories'); + $categories = $ci->config->item('categories'); $category_id = array_search($category_name, $categories); $results_data['category_name'] = $category_name; $results_data['category_id'] = $category_id; $results_data['category_title'] = $category_name ? - $this->lang->line("ui_categ_$category_name") : $category_name; + $ci->lang->line("ui_categ_$category_name") : $category_name; return $results_data; } diff --git a/application/controllers/user.php b/application/controllers/user.php index b9feb10..793d7f4 100644 --- a/application/controllers/user.php +++ b/application/controllers/user.php @@ -9,6 +9,7 @@ class User extends CI_Controller { private $import = FALSE; + private $activated_account = TRUE; public function __construct() { @@ -62,7 +63,9 @@ class User extends CI_Controller { } else { - if (! $this->import) + if (! $this->activated_account) + header('Location: '. site_url('catalog/test')); + else if (! $this->import) { // Redirect to last page before login. header('Location: '. site_url(urldecode_segments($redirect))); @@ -88,6 +91,8 @@ class User extends CI_Controller { { $this->session->unset_userdata('user_id'); $this->session->unset_userdata('username'); + $this->session->unset_userdata('auth_src'); + $this->session->unset_userdata('time_zone'); header('Location: '. site_url(urldecode_segments($redirect))); } @@ -106,11 +111,13 @@ class User extends CI_Controller { // Edit account data if logged in, otherwise register. if ($user_id = $this->session->userdata('user_id')) { - $userdata = $this->users_model->get_userdata($user_id); + $userdata = $this->users_model->get_userdata(intval($user_id)); + $selected_menu = 'account'; } else { $userdata = FALSE; + $selected_menu = 'register'; } $params = array('title' => @@ -125,7 +132,8 @@ class User extends CI_Controller { // ** LOADING VIEWS // ** $this->load->view('html_begin', $this->html_head_params); - $this->load->view('header', array('selected_menu' => 'register')); + $this->load->view('header', + array('selected_menu' => $selected_menu)); $main_params['content'] = $this->load->view('user/register_view', array('userdata'=> $userdata, 'redirect'=> $redirect), @@ -148,6 +156,9 @@ class User extends CI_Controller { $data['ui_lang'] = $this->input->post('ui-lang'); $data['time_zone'] = $this->input->post('time-zone'); + // Update session user data. + $this->_update_session_userdata($data); + // Edit account data if ($user_id) { @@ -176,6 +187,94 @@ class User extends CI_Controller { $this->register($redirect); } + public function profile($username, $videos_offset = 0) + { + // TODO handle user not found + + $this->load->config('localization'); + $this->load->helper('date'); + $this->lang->load('date'); + + // ** + // ** LOADING MODEL + // ** + // Logged in user time zone + $time_zone = $this->session->userdata('time_zone'); + if (! $time_zone) + $time_zone = 'UTC'; + + // User data + $userdata = $this->users_model->get_userdata($username); + $userdata['roles'] = Users_model::roles_to_string($userdata['roles']); + $country_list = $this->config->item('country_list'); + $userdata['country_name'] = $country_list[ $userdata['country'] ]; + $userdata['last_login'] = date('Y-m-d H:i:s', + gmt_to_local( + strtotime($userdata['last_login']), + $time_zone, + TRUE)) . ($time_zone == 'UTC' ? ' (UTC)' : ''); + $userdata['time_zone'] = $this->lang->line($userdata['time_zone']); + + // User's videos + $this->load->model('videos_model'); + $vs_data['videos'] = $this->videos_model->get_videos_summary( + NULL, $username, intval($videos_offset), + $this->config->item('videos_per_page')); + + // Pagination + $this->load->library('pagination'); + $pg_config['base_url'] = site_url("user/profile/$username/"); + $pg_config['uri_segment'] = 4; + $pg_config['total_rows'] = $this->videos_model->get_videos_count( + NULL, $username); + $pg_config['per_page'] = $this->config->item('videos_per_page'); + $this->pagination->initialize($pg_config); + $vs_data['pagination'] = $this->pagination->create_links(); + $vs_data['title'] = NULL; + $vs_data['category_name'] = ''; // TODO videos_summary with AJAX + + $params = array( + 'title'=> $this->lang->line('user_appelation').' '.$username + .' – ' + . $this->config->item('site_name'), + 'css'=> array('catalog.css') + //'metas' => array('description'=>'') + ); + $this->load->library('html_head_params', $params); + + // Current user profile tab + $tab = (! $videos_offset ? 0 : 1); + + // ** + // ** LOADING VIEWS + // ** + $this->load->view('html_begin', $this->html_head_params); + $this->load->view('header', array()); + + $vs = $this->load->view('catalog/videos_summary_view', $vs_data, TRUE); + + $main_params['content'] = $this->load->view('user/profile_view', + array('userdata'=> $userdata, 'videos_summary'=> $vs, 'tab'=>$tab), + 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'); + } + + public function activate($user_id, $activation_code) + { + $user_id = intval($user_id); + echo ''. $this->users_model->activate_account($user_id, $activation_code); + } + + public function _update_session_userdata($data) + { + foreach ($data as $key=> $val) + $this->session->set_userdata($key, $val); + } + public function _valid_username($username) { return (preg_match('/^[a-z0-9\._]+$/', $username) === 1); @@ -242,13 +341,21 @@ class User extends CI_Controller { if ($user === FALSE) return FALSE; + // User has not activated the account. + if ($user['activation_code'] !== NULL) + { + $this->activated_account = FALSE; + return TRUE; + } + // Authentication successful: set session with user data. $this->session->set_userdata(array( 'user_id'=> $user['id'], 'username'=> $user['username'], - 'auth_src'=> $user['auth_src'] + 'auth_src'=> $user['auth_src'], + 'time_zone'=> $user['time_zone'] )); - $this->import = $user['import']; + $this->import = (isset($user['import']) ? $user['import'] : FALSE); return TRUE; } } diff --git a/application/language/english/user_lang.php b/application/language/english/user_lang.php index a4a64cf..84cdd79 100644 --- a/application/language/english/user_lang.php +++ b/application/language/english/user_lang.php @@ -1,5 +1,7 @@ db->query("SELECT * FROM `users` + $query = $this->db->query("SELECT u.*, a.activation_code + FROM `users` u LEFT JOIN `users_unactivated` a ON (u.id = a.user_id) WHERE $cond_user AND (auth_src = 'ldap' OR password = '$enc_password')"); // It is possible that the user has a LDAP account but he's // authenticating here for the first time so it does not have an entry // in `users` table. - if ($query->num_rows() !== 1) + if ($query->num_rows() === 0) { $ldap_userdata = $this->ldap_login($username, $password); + if ($ldap_userdata === FALSE) + return FALSE; $userdata = $this->convert_ldap_userdata($ldap_userdata); $this->register($userdata); $user = $this->login($username, $password); $user['import'] = TRUE; return $user; - - /* foreach ($ldap_userdata as $k => $v) - { - echo "

$k

"; - print_r($v); - } - die(); */ } $user = $query->row_array(); // Authenticate with LDAP. - if ($user['auth_src'] == 'ldap') - return ($this->ldap_login($username, $password) !== FALSE - ? $user : FALSE); + if ($user['auth_src'] == 'ldap' + && ! $this->ldap_login($username, $password)) + return FALSE; + + // Update last login time. + $this->db->query("UPDATE `users` + SET last_login = UTC_TIMESTAMP() + WHERE username = '$username'"); // If we are here internal authentication has successful. return $user; @@ -184,6 +185,8 @@ class Users_model extends CI_Model { /** * Adds a new user to DB. + * Do not add join_date and last_login column, they will be automatically + * added. * * @param array $data corresponds to DB columns */ @@ -212,22 +215,78 @@ class Users_model extends CI_Model { $vals = substr($vals, 0, -2); $query = $this->db->query("INSERT INTO `users` - ($cols) - VALUES ($vals)"); + ($cols, registration_date, last_login) + VALUES ($vals, utc_timestamp(), utc_timestamp())"); + + if ($query === FALSE) + return FALSE; + + // If the registered with internal authentication it needs to activate + // the account. + $activation_code = Users_model::gen_activation_code(); + $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')"); // TODO exception on failure return $query; } + public function get_user_id($username) + { + $query = $this->db->query("SELECT id FROM `users` + WHERE username = '$username'"); + + if ($query->num_rows() === 0) + return FALSE; + + return $query->row()->id; + } + + // TODO cleanup account activation + public function cleanup_account_activation() + { + + } + /** - * Returns data from `users` table for user with $user_id. + * Activated an account for an user having $user_id with $activation_code. * * @param int $user_id + * @param string $activation_code hexa 16 characters string + * @return returns TRUE if activation was successful and FALSE otherwise + */ + public function activate_account($user_id, $activation_code) + { + $query = $this->db->query("SELECT * FROM `users_unactivated` + WHERE user_id = $user_id + AND activation_code = '$activation_code'"); + + if ($query->num_rows() === 0) + return FALSE; + + $this->db->query("DELETE FROM `users_unactivated` + WHERE user_id = $user_id"); + + 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. + * + * @param mixed $user */ - public function get_userdata($user_id) + public function get_userdata($user) { + if (is_int($user)) + $cond = "id = $user"; + else + $cond = "username = '$user'"; + $query = $this->db->query("SELECT * from `users` - WHERE id = $user_id"); + WHERE $cond"); if ($query->num_rows() === 0) return FALSE; @@ -269,6 +328,37 @@ class Users_model extends CI_Model { // TODO exception return $query; } + + public static function gen_activation_code($str = '') + { + $ci =& get_instance(); + + $activation_code = substr( + sha1(''. $str. $ci->config->item('encryption_key') + . mt_rand()), + 0, + 16); + + return $activation_code; + } + + public static function roles_to_string($roles) + { + $ci =& get_instance(); + $ci->lang->load('user'); + + if ($roles == USER_ROLE_STANDARD) + return $ci->lang->line('user_role_standard'); + else + { + $str_roles = ''; + + if ($roles & USER_ROLE_ADMIN) + $str_roles .= $ci->lang->line('user_role_admin') . '; '; + } + + return $str_roles; + } } /* End of file users_model.php */ diff --git a/application/models/videos_model.php b/application/models/videos_model.php index f92b07e..6a06e1c 100644 --- a/application/models/videos_model.php +++ b/application/models/videos_model.php @@ -21,10 +21,13 @@ class Videos_model extends CI_Model { } /** - * Retrieves information about a set of videos which are going to be - * displayed in the catalog. + * Retrieves a set of videos information which can be used for displaying + * that videos as a list with few details. * - * @param int $category_id DB category ID + * @param int $category_id DB category ID; pass NULL for all + * categories + * @param mixed $user an user_id (as int) or an username + * (as string); pass NULL for all users * @param int $offset * @param int $count * @param string $ordering control videos ording by these @@ -45,7 +48,8 @@ class Videos_model extends CI_Model { *
  • thumbs => thumbnail images' URLs
  • * */ - public function get_videos_summary($category_id, $offset, $count, $ordering = 'hottest') + public function get_videos_summary($category_id, $user, $offset, $count, + $ordering = 'hottest') { $this->load->helper('text'); @@ -66,19 +70,39 @@ class Videos_model extends CI_Model { $order_statement = ""; } + // Category filtering + if ($category_id === NULL) + $cond_category = "1"; + else + { + $category_id = intval($category_id); + $cond_category = "category_id = $category_id"; + } + + // User filtering + if ($user === NULL) + $cond_user = "1"; + else + { + if (is_int($user)) + $cond_user = "v.user_id = $user"; + else if (is_string($user)) + $cond_user = "u.username = '$user'"; + } + $query = $this->db->query( - "SELECT id, name, title, duration, user_id, views, thumbs_count, - default_thumb, (views + likes - dislikes) AS score - FROM `videos` - WHERE category_id = ? + "SELECT v.id, name, title, duration, user_id, u.username, views, + thumbs_count, default_thumb, + (views + likes - dislikes) AS score + FROM `videos` v, `users` u + WHERE v.user_id = u.id AND $cond_category AND $cond_user $order_statement - LIMIT ?, ?", - array(intval($category_id), $offset, $count)); + LIMIT $offset, $count"); if ($query->num_rows() > 0) $videos = $query->result_array(); else - return NULL; + return array(); foreach ($videos as & $video) { @@ -93,21 +117,41 @@ class Videos_model extends CI_Model { // Ellipsized title //$video['shorted_title'] = ellipsize($video['title'], 45, 0.75); $video['shorted_title'] = character_limiter($video['title'], 50); - - // TODO: user information - $video['user_name'] = 'TODO'; } return $videos; } - public function get_videos_count($category_id) + /** + * Returns the number of videos from database from a specific category or + * user. + * NULL parameters count videos from all categories and / or all users. + * + * @param int $category_id + * @param mixed $user an user_id (as int) or an username (as string) + * @return int number of videos or NULL if an error occured + */ + public function get_videos_count($category_id = NULL, $user = NULL) { + if ($category_id === NULL) + $cond_category = "1"; + else + $cond_category = "category_id = $category_id"; + + if ($user === NULL) + $cond_user = "1"; + else + { + if (is_int($user)) + $cond_user = "v.user_id = $user"; + else if(is_string($user)) + $cond_user = "u.username = '$user'"; + } + $query = $this->db->query( - 'SELECT COUNT(*) count - FROM `videos` - WHERE category_id = ?', - $category_id); + "SELECT COUNT(*) count + FROM `videos` v, `users` u + WHERE v.user_id = u.id AND $cond_category AND $cond_user"); if ($query->num_rows() > 0) return $query->row()->count; diff --git a/application/views/catalog/category_view.php b/application/views/catalog/category_view.php deleted file mode 100644 index c4c2ba3..0000000 --- a/application/views/catalog/category_view.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/application/views/catalog/index_view.php b/application/views/catalog/index_view.php index 03ab7e5..9f4a519 100644 --- a/application/views/catalog/index_view.php +++ b/application/views/catalog/index_view.php @@ -1,3 +1,8 @@ - \ No newline at end of file + +

    + "> + + +

    + + \ No newline at end of file diff --git a/application/views/catalog/videos_summary_view.php b/application/views/catalog/videos_summary_view.php index 66e5f29..42d0683 100644 --- a/application/views/catalog/videos_summary_view.php +++ b/application/views/catalog/videos_summary_view.php @@ -1,9 +1,9 @@
    -

    - "> - - + +

    +

    + + +

    lang->line('user_no_videos_uploaded') ?>

    + @@ -44,10 +47,11 @@ ?>
    - lang->line('ui_from') . ' TODO' //TODO ?> + lang->line('ui_from') ?> ">
    + @@ -55,6 +59,7 @@ + \ No newline at end of file diff --git a/application/views/user/register_view.php b/application/views/user/register_view.php index f5398d6..42159c2 100644 --- a/application/views/user/register_view.php +++ b/application/views/user/register_view.php @@ -43,7 +43,7 @@ endif; lang->line('user_username'). ': ' ?> -   +   ` diff --git a/css/catalog.css b/css/catalog.css index 93e58c6..9d371a4 100644 --- a/css/catalog.css +++ b/css/catalog.css @@ -22,11 +22,6 @@ margin-left: 8px; } -.category-title -{ - /* border-bottom: 1px solid rgb(108,162,222); */ -} - .video-icon { position: relative; @@ -34,7 +29,7 @@ float: left; width: 146px; height: 170px; - margin-right: 4px; + padding-right: 4px; } .video-icon .video-thumb @@ -76,6 +71,7 @@ { margin-top: 2px; font-size: 1em; + text-align: left; line-height: 100%; } .video-icon .video-views diff --git a/css/default.css b/css/default.css index e958f38..16073af 100644 --- a/css/default.css +++ b/css/default.css @@ -33,6 +33,7 @@ table.form th } table.form td { + padding-left: 0.5em; vertical-align: top; }