PageRenderTime 26ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/application/models/user.php

http://github.com/ushahidi/Ushahidi_Web
PHP | 381 lines | 206 code | 51 blank | 124 comment | 27 complexity | 9921a182f124813ee66949633fc94491 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * Model for users for the Auth Module
  4. *
  5. * $Id: user.php 3352 2008-08-18 09:43:56BST atomless $
  6. *
  7. * PHP version 5
  8. * LICENSE: This source file is subject to LGPL license
  9. * that is available through the world-wide-web at the following URI:
  10. * http://www.gnu.org/copyleft/lesser.html
  11. * @author Ushahidi Team <team@ushahidi.com>
  12. * @package Ushahidi - http://source.ushahididev.com
  13. * @subpackage Models
  14. * @copyright Ushahidi - http://www.ushahidi.com
  15. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License (LGPL)
  16. */
  17. class User_Model extends Auth_User_Model {
  18. protected $has_many = array('alert', 'comment', 'openid', 'private_message', 'rating');
  19. /**
  20. * Creates a basic user and assigns to login and member roles
  21. *
  22. * @param string email
  23. * @param string password
  24. * @param string riverid user id
  25. * @return object ORM object from saving the user
  26. */
  27. public static function create_user($email, $password, $riverid=FALSE, $name=FALSE)
  28. {
  29. $user = ORM::factory('user');
  30. $user->email = $email;
  31. $user->username = User_Model::random_username();
  32. $user->password = $password;
  33. if (! empty($name))
  34. {
  35. $user->name = $name;
  36. }
  37. else
  38. {
  39. $user->needinfo = 1;
  40. }
  41. $user->riverid = ( $riverid == false ) ? '' : $riverid;
  42. // Add New Roles if:
  43. // 1. We don't require admin to approve users (will be added when admin approves)
  44. // 2. We don't require users to first confirm their email address (will be added
  45. // when user confirms if the admin doesn't have to first approve the user)
  46. if (Kohana::config('settings.manually_approve_users') == 0
  47. AND Kohana::config('settings.require_email_confirmation') == 0)
  48. {
  49. $user->add(ORM::factory('role', 'login'));
  50. $user->add(ORM::factory('role', 'member'));
  51. }
  52. return $user->save();
  53. }
  54. /**
  55. * Gets the email address of a user
  56. * @return string
  57. */
  58. public static function get_email($user_id)
  59. {
  60. $user = ORM::factory('user')->find($user_id);
  61. return $user->email;
  62. }
  63. /**
  64. * Returns data for a user based on username
  65. * @return object
  66. */
  67. public static function get_user_by_username($username)
  68. {
  69. $user = ORM::factory('user')->where(array('username'=>$username))->find();
  70. return $user;
  71. }
  72. /**
  73. * Returns data for a user based on email
  74. * @return object
  75. */
  76. public static function get_user_by_email($email)
  77. {
  78. $user = ORM::factory('user')->where(array('email'=>$email))->find();
  79. return $user;
  80. }
  81. /**
  82. * Returns data for a user based on user id
  83. * @return object
  84. */
  85. public static function get_user_by_id($user_id)
  86. {
  87. $user = ORM::factory('user')->where(array('id'=>$user_id))->find();
  88. return $user;
  89. }
  90. /**
  91. * Returns data for a user based on river id
  92. * @return object
  93. */
  94. public static function get_user_by_river_id($river_id)
  95. {
  96. $user = ORM::factory('user')->where(array('riverid'=>$river_id))->find();
  97. return $user;
  98. }
  99. /**
  100. * Returns all users with public profiles
  101. * @return object
  102. */
  103. public static function get_public_users()
  104. {
  105. $users = ORM::factory('user')
  106. ->where(array('public_profile'=>1)) // Only show public profiles
  107. ->notlike(array('username'=>'@')) // We only want to show profiles that don't have email addresses as usernames
  108. ->find_all();
  109. return $users;
  110. }
  111. /**
  112. * Custom validation for this model - complements the default validate()
  113. *
  114. * @param array array to validate
  115. * @param Auth instance of Auth class; used for testing purposes
  116. * @return bool TRUE if validation succeeds, FALSE otherwise
  117. */
  118. public static function custom_validate(array & $post, Auth $auth = NULL)
  119. {
  120. // Initalize validation
  121. $post = Validation::factory($post)
  122. ->pre_filter('trim', TRUE);
  123. if ($auth === NULL)
  124. {
  125. $auth = new Auth;
  126. }
  127. $post->add_rules('username','required','length[3,100]', 'alpha_numeric');
  128. $post->add_rules('name','required','length[3,100]');
  129. $post->add_rules('email','required','email','length[4,64]');
  130. // If user id is not specified, check if the username already exists
  131. if (empty($post->user_id))
  132. {
  133. $post->add_callbacks('username', array('User_Model', 'unique_value_exists'));
  134. $post->add_callbacks('email', array('User_Model', 'unique_value_exists'));
  135. }
  136. // Make sure we have a value for password length to avoid PHP error for missing length[] function
  137. $password_length = Kohana::config('auth.password_length');
  138. $password_length = ( ! empty($password_length)) ? $password_length : '1,127';
  139. // Only check for the password if the user id has been specified and we are passing a pw
  140. if (isset($post->user_id) AND isset($post->password))
  141. {
  142. $post->add_rules('password','required', 'length['.$password_length.']');
  143. }
  144. // If Password field is not blank and is being passed
  145. if ( isset($post->password) AND
  146. (! empty($post->password) OR (empty($post->password) AND ! empty($post->password_again))))
  147. {
  148. $post->add_rules('password','required','length['.$password_length.']', 'matches[password_again]');
  149. }
  150. $post->add_rules('role','required','length[3,30]', 'alpha_numeric');
  151. $post->add_rules('notify','between[0,1]');
  152. if ( ! $auth->logged_in('superadmin'))
  153. {
  154. $post->add_callbacks('role', array('User_Model', 'prevent_superadmin_modification'));
  155. }
  156. // Additional validation checks
  157. Event::run('ushahidi_action.user_submit_admin', $post);
  158. // Return
  159. return $post->validate();
  160. }
  161. /**
  162. * Checks if a password is correct
  163. *
  164. * @param int user id
  165. * @param string password to check
  166. * @return bool TRUE if the password matches, FALSE otherwise
  167. */
  168. public static function check_password($user_id,$password,$force_standard_method=FALSE)
  169. {
  170. $user = ORM::factory('user',$user_id);
  171. // RiverID or Standard method?
  172. if (kohana::config('riverid.enable') == TRUE
  173. AND ! empty($user->riverid)
  174. AND ! $force_standard_method)
  175. {
  176. // RiverID
  177. $riverid = new RiverID;
  178. $riverid->email = $user->email;
  179. $riverid->password = $password;
  180. if ($riverid->checkpassword() != FALSE)
  181. {
  182. return TRUE;
  183. }
  184. else
  185. {
  186. // TODO: Maybe return the error message?
  187. return FALSE;
  188. }
  189. }
  190. else
  191. {
  192. // Standard Local
  193. $auth = Auth::instance();
  194. return $auth->check_password($user_id,$password);
  195. }
  196. }
  197. /**
  198. * Checks if the value in the specified field exists in database
  199. */
  200. public static function unique_value_exists(Validation $post, $field)
  201. {
  202. $exists = (bool) ORM::factory('user')->where($field, $post[$field])->count_all();
  203. if ($exists)
  204. {
  205. $post->add_error($field, 'exists');
  206. }
  207. }
  208. /**
  209. * Ensures that only a superadmin can modify superadmin users, or upgrade a user to superadmin
  210. * @note this assumes the currently logged-in user isn't a superadmin
  211. */
  212. public static function prevent_superadmin_modification(Validation $post, $field)
  213. {
  214. if ($post[$field] == 'superadmin')
  215. {
  216. $post->add_error($field, 'superadmin_modify');
  217. }
  218. }
  219. /*
  220. * Creates a random int value for a username that isn't already represented in the database
  221. */
  222. public function random_username()
  223. {
  224. while ($random = mt_rand(1000,mt_getrandmax()))
  225. {
  226. $find_username = ORM::factory('user')->where('username',$random)->count_all();
  227. if ($find_username == 0)
  228. {
  229. return $random;
  230. }
  231. }
  232. return FALSE;
  233. }
  234. /**
  235. * Overrides the default delete method for the ORM.
  236. * Deletes roles associated with the user before user is removed from DB.
  237. */
  238. public function delete()
  239. {
  240. $table_prefix = Kohana::config('database.default.table_prefix');
  241. // Remove assigned roles
  242. // Have to use db->query() since we don't have an ORM model for roles_users
  243. $this->db->query('DELETE FROM `'.$table_prefix.'roles_users` WHERE user_id = ?',$this->id);
  244. // Remove assigned badges
  245. $this->db->query('DELETE FROM `'.$table_prefix.'badge_users` WHERE user_id = ?',$this->id);
  246. // Delete alerts
  247. ORM::factory('alert')
  248. ->where('user_id', $this->id)
  249. ->delete_all();
  250. // Delete user_token
  251. ORM::factory('user_token')
  252. ->where('user_id', $this->id)
  253. ->delete_all();
  254. // Delete openid
  255. ORM::factory('openid')
  256. ->where('user_id', $this->id)
  257. ->delete_all();
  258. parent::delete();
  259. }
  260. /**
  261. * Check if user has specified permission
  262. * @param $permission String permission name
  263. **/
  264. public function has_permission($permission)
  265. {
  266. // Cache superadmin role to avoid repeating query
  267. static $superadmin;
  268. if (!isset($superadmin)) $superadmin = ORM::factory('role','superadmin');
  269. // Special case - superadmin ALWAYS has all permissions
  270. if ($this->has($superadmin))
  271. {
  272. return TRUE;
  273. }
  274. foreach ($this->roles as $user_role)
  275. {
  276. if ($user_role->has(ORM::factory('permission',$permission)))
  277. {
  278. return TRUE;
  279. }
  280. }
  281. return FALSE;
  282. }
  283. /**
  284. * Get user's dashboard
  285. */
  286. public function dashboard()
  287. {
  288. if ($this->has_permission('admin_ui'))
  289. return 'admin';
  290. if ($this->has_permission('member_ui'))
  291. return 'members';
  292. // Just in case someone has a login only role
  293. if ($this->has(ORM::factory('role','login')))
  294. return '';
  295. // Send anyone else to login
  296. return 'login';
  297. }
  298. /**
  299. * Get a new forgotten password challenge token for this user
  300. * @param string $salt Optional salt for token generation (use this)
  301. * @return string
  302. */
  303. public function forgot_password_token()
  304. {
  305. return $this->_forgot_password_token();
  306. }
  307. /**
  308. * Check to see if forgotten password token is valid
  309. * @param string $token token to check
  310. * @return boolean is token valid
  311. **/
  312. public function check_forgot_password_token($token)
  313. {
  314. $salt = substr($token, 0, 32);
  315. return $this->_forgot_password_token($salt) == $token;
  316. }
  317. /**
  318. * Generate a forgotten password challenge token for this user
  319. * @param string $salt Optional salt for token generation (only use this for checking a token in URL)
  320. * @return string token
  321. */
  322. private function _forgot_password_token($salt = FALSE)
  323. {
  324. // Hashed datq consists of email and the last_login field
  325. // So as soon as the user logs in again, the reset link expires automatically.
  326. $salt = $salt ? $salt : text::random('alnum', 32); // Limited charset to keep it URL friendly
  327. $key = Kohana::config('settings.forgot_password_secret');
  328. return $salt . hash_hmac('sha1', $this->last_login . $this->email, $salt . $key);
  329. }
  330. } // End User_Model