PageRenderTime 64ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/Users/Controller/UsersController.php

https://github.com/kareypowell/croogo
PHP | 588 lines | 372 code | 52 blank | 164 comment | 60 complexity | 0f1e29acb6a153ada0bd2725c347fbb4 MD5 | raw file
  1. <?php
  2. App::uses('CakeEmail', 'Network/Email');
  3. App::uses('UsersAppController', 'Users.Controller');
  4. /**
  5. * Users Controller
  6. *
  7. * @category Controller
  8. * @package Croogo.Users.Controller
  9. * @version 1.0
  10. * @author Fahad Ibnay Heylaal <contact@fahad19.com>
  11. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  12. * @link http://www.croogo.org
  13. */
  14. class UsersController extends UsersAppController {
  15. /**
  16. * Components
  17. *
  18. * @var array
  19. * @access public
  20. */
  21. public $components = array(
  22. 'Search.Prg' => array(
  23. 'presetForm' => array(
  24. 'paramType' => 'querystring',
  25. ),
  26. 'commonProcess' => array(
  27. 'paramType' => 'querystring',
  28. 'filterEmpty' => true,
  29. ),
  30. ),
  31. );
  32. /**
  33. * Preset Variables Search
  34. *
  35. * @var array
  36. * @access public
  37. */
  38. public $presetVars = true;
  39. /**
  40. * Models used by the Controller
  41. *
  42. * @var array
  43. * @access public
  44. */
  45. public $uses = array('Users.User');
  46. /**
  47. * implementedEvents
  48. *
  49. * @return array
  50. */
  51. public function implementedEvents() {
  52. return parent::implementedEvents() + array(
  53. 'Controller.Users.beforeAdminLogin' => 'onBeforeAdminLogin',
  54. 'Controller.Users.adminLoginFailure' => 'onAdminLoginFailure',
  55. );
  56. }
  57. /**
  58. * Notify user when failed_login_limit hash been hit
  59. *
  60. * @return bool
  61. */
  62. public function onBeforeAdminLogin() {
  63. $field = $this->Auth->authenticate['all']['fields']['username'];
  64. if (empty($this->request->data)) {
  65. return true;
  66. }
  67. $cacheName = 'auth_failed_' . $this->request->data['User'][$field];
  68. $cacheValue = Cache::read($cacheName, 'users_login');
  69. if ($cacheValue >= Configure::read('User.failed_login_limit')) {
  70. $this->Session->setFlash(__d('croogo', 'You have reached maximum limit for failed login attempts. Please try again after a few minutes.'), 'default', array('class' => 'error'));
  71. return $this->redirect(array('action' => $this->request->params['action']));
  72. }
  73. return true;
  74. }
  75. /**
  76. * Record the number of times a user has failed authentication in cache
  77. *
  78. * @return bool
  79. * @access public
  80. */
  81. public function onAdminLoginFailure() {
  82. $field = $this->Auth->authenticate['all']['fields']['username'];
  83. if (empty($this->request->data)) {
  84. return true;
  85. }
  86. $cacheName = 'auth_failed_' . $this->request->data['User'][$field];
  87. $cacheValue = Cache::read($cacheName, 'users_login');
  88. Cache::write($cacheName, (int)$cacheValue + 1, 'users_login');
  89. return true;
  90. }
  91. /**
  92. * Admin index
  93. *
  94. * @return void
  95. * @access public
  96. * $searchField : Identify fields for search
  97. */
  98. public function admin_index() {
  99. $this->set('title_for_layout', __d('croogo', 'Users'));
  100. $this->Prg->commonProcess();
  101. $searchFields = array('role_id', 'name');
  102. $this->User->recursive = 0;
  103. $criteria = $this->User->parseCriteria($this->Prg->parsedParams());
  104. $this->paginate['conditions'] = $criteria;
  105. $this->set('users', $this->paginate());
  106. $this->set('roles', $this->User->Role->find('list'));
  107. $this->set('displayFields', $this->User->displayFields());
  108. $this->set('searchFields', $searchFields);
  109. if (isset($this->request->query['chooser'])) {
  110. $this->layout = 'admin_popup';
  111. }
  112. }
  113. /**
  114. * Send activation email
  115. */
  116. private function __sendActivationEmail() {
  117. if (empty($this->request->data['User']['notification'])) {
  118. return;
  119. }
  120. $user = $this->request->data['User'];
  121. $activationUrl = Router::url(array(
  122. 'admin' => false,
  123. 'plugin' => 'users',
  124. 'controller' => 'users',
  125. 'action' => 'activate',
  126. $user['username'],
  127. $user['activation_key'],
  128. ), true);
  129. $this->_sendEmail(
  130. array(Configure::read('Site.title'), $this->_getSenderEmail()),
  131. $user['email'],
  132. __d('croogo', '[%s] Please activate your account', Configure::read('Site.title')),
  133. 'Users.register',
  134. 'user activation',
  135. $this->theme,
  136. array(
  137. 'user' => $this->request->data,
  138. 'url' => $activationUrl,
  139. )
  140. );
  141. }
  142. /**
  143. * Admin add
  144. *
  145. * @return void
  146. * @access public
  147. */
  148. public function admin_add() {
  149. if (!empty($this->request->data)) {
  150. $this->User->create();
  151. $this->request->data['User']['activation_key'] = md5(uniqid());
  152. if ($this->User->save($this->request->data)) {
  153. $this->request->data['User']['id'] = $this->User->id;
  154. $this->__sendActivationEmail();
  155. $this->Session->setFlash(__d('croogo', 'The User has been saved'), 'default', array('class' => 'success'));
  156. return $this->redirect(array('action' => 'index'));
  157. } else {
  158. $this->Session->setFlash(__d('croogo', 'The User could not be saved. Please, try again.'), 'default', array('class' => 'error'));
  159. unset($this->request->data['User']['password']);
  160. }
  161. } else {
  162. $this->request->data['User']['role_id'] = 2; // default Role: Registered
  163. }
  164. $roles = $this->User->Role->find('list');
  165. $this->set(compact('roles'));
  166. }
  167. /**
  168. * Admin edit
  169. *
  170. * @param integer $id
  171. * @return void
  172. * @access public
  173. */
  174. public function admin_edit($id = null) {
  175. if (!empty($this->request->data)) {
  176. if ($this->User->save($this->request->data)) {
  177. $this->Session->setFlash(__d('croogo', 'The User has been saved'), 'default', array('class' => 'success'));
  178. return $this->Croogo->redirect(array('action' => 'edit', $this->User->id));
  179. } else {
  180. $this->Session->setFlash(__d('croogo', 'The User could not be saved. Please, try again.'), 'default', array('class' => 'error'));
  181. }
  182. } else {
  183. $this->request->data = $this->User->read(null, $id);
  184. }
  185. $roles = $this->User->Role->find('list');
  186. $this->set(compact('roles'));
  187. $this->set('editFields', $this->User->editFields());
  188. }
  189. /**
  190. * Admin reset password
  191. *
  192. * @param integer $id
  193. * @return void
  194. * @access public
  195. */
  196. public function admin_reset_password($id = null) {
  197. if (!$id && empty($this->request->data)) {
  198. $this->Session->setFlash(__d('croogo', 'Invalid User'), 'default', array('class' => 'error'));
  199. return $this->redirect(array('action' => 'index'));
  200. }
  201. if (!empty($this->request->data)) {
  202. if ($this->User->save($this->request->data)) {
  203. $this->Session->setFlash(__d('croogo', 'Password has been reset.'), 'default', array('class' => 'success'));
  204. return $this->redirect(array('action' => 'index'));
  205. } else {
  206. $this->Session->setFlash(__d('croogo', 'Password could not be reset. Please, try again.'), 'default', array('class' => 'error'));
  207. }
  208. }
  209. $this->request->data = $this->User->findById($id);
  210. }
  211. /**
  212. * Admin delete
  213. *
  214. * @param integer $id
  215. * @return void
  216. * @access public
  217. */
  218. public function admin_delete($id = null) {
  219. if (!$id) {
  220. $this->Session->setFlash(__d('croogo', 'Invalid id for User'), 'default', array('class' => 'error'));
  221. return $this->redirect(array('action' => 'index'));
  222. }
  223. if ($this->User->delete($id)) {
  224. $this->Session->setFlash(__d('croogo', 'User deleted'), 'default', array('class' => 'success'));
  225. return $this->redirect(array('action' => 'index'));
  226. } else {
  227. $this->Session->setFlash(__d('croogo', 'User cannot be deleted'), 'default', array('class' => 'error'));
  228. return $this->redirect(array('action' => 'index'));
  229. }
  230. }
  231. /**
  232. * Admin login
  233. *
  234. * @return void
  235. * @access public
  236. */
  237. public function admin_login() {
  238. $this->set('title_for_layout', __d('croogo', 'Admin Login'));
  239. $this->layout = "admin_login";
  240. if ($this->Auth->user('id')) {
  241. if (!$this->Session->check('Message.auth')) {
  242. $this->Session->setFlash(
  243. __d('croogo', 'You are already logged in'), 'default',
  244. array('class' => 'alert'), 'auth'
  245. );
  246. }
  247. return $this->redirect($this->Auth->redirect());
  248. }
  249. if ($this->request->is('post')) {
  250. Croogo::dispatchEvent('Controller.Users.beforeAdminLogin', $this);
  251. if ($this->Auth->login()) {
  252. Croogo::dispatchEvent('Controller.Users.adminLoginSuccessful', $this);
  253. return $this->redirect($this->Auth->redirect());
  254. } else {
  255. Croogo::dispatchEvent('Controller.Users.adminLoginFailure', $this);
  256. $this->Auth->authError = __d('croogo', 'Incorrect username or password');
  257. $this->Session->setFlash($this->Auth->authError, 'default', array('class' => 'error'), 'auth');
  258. return $this->redirect($this->Auth->loginAction);
  259. }
  260. }
  261. }
  262. /**
  263. * Admin logout
  264. *
  265. * @return void
  266. * @access public
  267. */
  268. public function admin_logout() {
  269. Croogo::dispatchEvent('Controller.Users.adminLogoutSuccessful', $this);
  270. $this->Session->setFlash(__d('croogo', 'Log out successful.'), 'default', array('class' => 'success'));
  271. return $this->redirect($this->Auth->logout());
  272. }
  273. /**
  274. * Index
  275. *
  276. * @return void
  277. * @access public
  278. */
  279. public function index() {
  280. $this->set('title_for_layout', __d('croogo', 'Users'));
  281. }
  282. /**
  283. * Convenience method to send email
  284. *
  285. * @param string $from Sender email
  286. * @param string $to Receiver email
  287. * @param string $subject Subject
  288. * @param string $template Template to use
  289. * @param string $theme Theme to use
  290. * @param array $viewVars Vars to use inside template
  291. * @param string $emailType user activation, reset password, used in log message when failing.
  292. * @return boolean True if email was sent, False otherwise.
  293. */
  294. protected function _sendEmail($from, $to, $subject, $template, $emailType, $theme = null, $viewVars = null) {
  295. if (is_null($theme)) {
  296. $theme = $this->theme;
  297. }
  298. $success = false;
  299. try {
  300. $email = new CakeEmail();
  301. $email->from($from[1], $from[0]);
  302. $email->to($to);
  303. $email->subject($subject);
  304. $email->template($template);
  305. $email->viewVars($viewVars);
  306. $email->theme($theme);
  307. $success = $email->send();
  308. } catch (SocketException $e) {
  309. $this->log(sprintf('Error sending %s notification : %s', $emailType, $e->getMessage()));
  310. }
  311. return $success;
  312. }
  313. /**
  314. * Add
  315. *
  316. * @return void
  317. * @access public
  318. */
  319. public function add() {
  320. $this->set('title_for_layout', __d('croogo', 'Register'));
  321. if (!empty($this->request->data)) {
  322. $this->User->create();
  323. $this->request->data['User']['role_id'] = 2; // Registered
  324. $this->request->data['User']['activation_key'] = md5(uniqid());
  325. $this->request->data['User']['status'] = 0;
  326. $this->request->data['User']['username'] = htmlspecialchars($this->request->data['User']['username']);
  327. $this->request->data['User']['website'] = htmlspecialchars($this->request->data['User']['website']);
  328. $this->request->data['User']['name'] = htmlspecialchars($this->request->data['User']['name']);
  329. if ($this->User->save($this->request->data)) {
  330. Croogo::dispatchEvent('Controller.Users.registrationSuccessful', $this);
  331. $this->request->data['User']['password'] = null;
  332. $this->_sendEmail(
  333. array(Configure::read('Site.title'), $this->_getSenderEmail()),
  334. $this->request->data['User']['email'],
  335. __d('croogo', '[%s] Please activate your account', Configure::read('Site.title')),
  336. 'Users.register',
  337. 'user activation',
  338. $this->theme,
  339. array('user' => $this->request->data)
  340. );
  341. $this->Session->setFlash(__d('croogo', 'You have successfully registered an account. An email has been sent with further instructions.'), 'default', array('class' => 'success'));
  342. return $this->redirect(array('action' => 'login'));
  343. } else {
  344. Croogo::dispatchEvent('Controller.Users.registrationFailure', $this);
  345. $this->Session->setFlash(__d('croogo', 'The User could not be saved. Please, try again.'), 'default', array('class' => 'error'));
  346. }
  347. }
  348. }
  349. /**
  350. * Activate
  351. *
  352. * @param string $username
  353. * @param string $key
  354. * @return void
  355. * @access public
  356. */
  357. public function activate($username = null, $key = null) {
  358. if ($username == null || $key == null) {
  359. return $this->redirect(array('action' => 'login'));
  360. }
  361. if ($this->Auth->user('id')) {
  362. $this->Session->setFlash(
  363. __d('croogo', 'You are currently logged in as:') . ' ' .
  364. $this->Auth->user('username')
  365. );
  366. return $this->redirect($this->referer());
  367. }
  368. $redirect = array('action' => 'login');
  369. if (
  370. $this->User->hasAny(array(
  371. 'User.username' => $username,
  372. 'User.activation_key' => $key,
  373. 'User.status' => 0,
  374. ))
  375. ) {
  376. $user = $this->User->findByUsername($username);
  377. $this->User->id = $user['User']['id'];
  378. $db = $this->User->getDataSource();
  379. $key = md5(uniqid());
  380. $this->User->updateAll(array(
  381. $this->User->escapeField('status') => $db->value(1),
  382. $this->User->escapeField('activation_key') => $db->value($key),
  383. ), array(
  384. $this->User->escapeField('id') => $this->User->id
  385. ));
  386. if (isset($user) && empty($user['User']['password'])) {
  387. $redirect = array('action' => 'reset', $username, $key);
  388. }
  389. Croogo::dispatchEvent('Controller.Users.activationSuccessful', $this);
  390. $this->Session->setFlash(__d('croogo', 'Account activated successfully.'), 'default', array('class' => 'success'));
  391. } else {
  392. Croogo::dispatchEvent('Controller.Users.activationFailure', $this);
  393. $this->Session->setFlash(__d('croogo', 'An error occurred.'), 'default', array('class' => 'error'));
  394. }
  395. if ($redirect) {
  396. return $this->redirect($redirect);
  397. }
  398. }
  399. /**
  400. * Edit
  401. *
  402. * @return void
  403. * @access public
  404. */
  405. public function edit() {
  406. }
  407. /**
  408. * Forgot
  409. *
  410. * @return void
  411. * @access public
  412. */
  413. public function forgot() {
  414. $this->set('title_for_layout', __d('croogo', 'Forgot Password'));
  415. if (!empty($this->request->data) && isset($this->request->data['User']['username'])) {
  416. $user = $this->User->findByUsername($this->request->data['User']['username']);
  417. if (!isset($user['User']['id'])) {
  418. $this->Session->setFlash(__d('croogo', 'Invalid username.'), 'default', array('class' => 'error'));
  419. return $this->redirect(array('action' => 'login'));
  420. }
  421. $this->User->id = $user['User']['id'];
  422. $activationKey = md5(uniqid());
  423. $this->User->saveField('activation_key', $activationKey);
  424. $this->set(compact('user', 'activationKey'));
  425. $emailSent = $this->_sendEmail(
  426. array(Configure::read('Site.title'), $this->_getSenderEmail()),
  427. $user['User']['email'],
  428. __d('croogo', '[%s] Reset Password', Configure::read('Site.title')),
  429. 'Users.forgot_password',
  430. 'reset password',
  431. $this->theme,
  432. compact('user', 'activationKey')
  433. );
  434. if ($emailSent) {
  435. $this->Session->setFlash(__d('croogo', 'An email has been sent with instructions for resetting your password.'), 'default', array('class' => 'success'));
  436. return $this->redirect(array('action' => 'login'));
  437. } else {
  438. $this->Session->setFlash(__d('croogo', 'An error occurred. Please try again.'), 'default', array('class' => 'error'));
  439. }
  440. }
  441. }
  442. /**
  443. * Reset
  444. *
  445. * @param string $username
  446. * @param string $key
  447. * @return void
  448. * @access public
  449. */
  450. public function reset($username = null, $key = null) {
  451. $this->set('title_for_layout', __d('croogo', 'Reset Password'));
  452. if ($username == null || $key == null) {
  453. $this->Session->setFlash(__d('croogo', 'An error occurred.'), 'default', array('class' => 'error'));
  454. return $this->redirect(array('action' => 'login'));
  455. }
  456. $user = $this->User->find('first', array(
  457. 'conditions' => array(
  458. 'User.username' => $username,
  459. 'User.activation_key' => $key,
  460. ),
  461. ));
  462. if (!isset($user['User']['id'])) {
  463. $this->Session->setFlash(__d('croogo', 'An error occurred.'), 'default', array('class' => 'error'));
  464. return $this->redirect(array('action' => 'login'));
  465. }
  466. if (!empty($this->request->data) && isset($this->request->data['User']['password'])) {
  467. $this->User->id = $user['User']['id'];
  468. $user['User']['activation_key'] = md5(uniqid());
  469. $user['User']['password'] = $this->request->data['User']['password'];
  470. $user['User']['verify_password'] = $this->request->data['User']['verify_password'];
  471. $options = array('fieldList' => array('password', 'verify_password', 'activation_key'));
  472. if ($this->User->save($user['User'], $options)) {
  473. $this->Session->setFlash(__d('croogo', 'Your password has been reset successfully.'), 'default', array('class' => 'success'));
  474. return $this->redirect(array('action' => 'login'));
  475. } else {
  476. $this->Session->setFlash(__d('croogo', 'An error occurred. Please try again.'), 'default', array('class' => 'error'));
  477. }
  478. }
  479. $this->set(compact('user', 'username', 'key'));
  480. }
  481. /**
  482. * Login
  483. *
  484. * @return boolean
  485. * @access public
  486. */
  487. public function login() {
  488. $this->set('title_for_layout', __d('croogo', 'Log in'));
  489. if ($this->request->is('post')) {
  490. Croogo::dispatchEvent('Controller.Users.beforeLogin', $this);
  491. if ($this->Auth->login()) {
  492. Croogo::dispatchEvent('Controller.Users.loginSuccessful', $this);
  493. return $this->redirect($this->Auth->redirect());
  494. } else {
  495. Croogo::dispatchEvent('Controller.Users.loginFailure', $this);
  496. $this->Session->setFlash($this->Auth->authError, 'default', array('class' => 'error'), 'auth');
  497. return $this->redirect($this->Auth->loginAction);
  498. }
  499. }
  500. }
  501. /**
  502. * Logout
  503. *
  504. * @return void
  505. * @access public
  506. */
  507. public function logout() {
  508. Croogo::dispatchEvent('Controller.Users.beforeLogout', $this);
  509. $this->Session->setFlash(__d('croogo', 'Log out successful.'), 'default', array('class' => 'success'));
  510. $redirect = $this->Auth->logout();
  511. Croogo::dispatchEvent('Controller.Users.afterLogout', $this);
  512. return $this->redirect($redirect);
  513. }
  514. /**
  515. * View
  516. *
  517. * @param string $username
  518. * @return void
  519. * @access public
  520. */
  521. public function view($username = null) {
  522. if ($username == null) {
  523. $username = $this->Auth->user('username');
  524. }
  525. $user = $this->User->findByUsername($username);
  526. if (!isset($user['User']['id'])) {
  527. $this->Session->setFlash(__d('croogo', 'Invalid User.'), 'default', array('class' => 'error'));
  528. return $this->redirect('/');
  529. }
  530. $this->set('title_for_layout', $user['User']['name']);
  531. $this->set(compact('user'));
  532. }
  533. protected function _getSenderEmail() {
  534. return 'croogo@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
  535. }
  536. }