PageRenderTime 176ms CodeModel.GetById 23ms RepoModel.GetById 4ms app.codeStats 0ms

/model/user.php

https://github.com/onliners/Goteo
PHP | 1209 lines | 824 code | 150 blank | 235 comment | 153 complexity | edff4a6011df520ca9ee086c70d307f0 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /*
  3. * Copyright (C) 2012 Platoniq y Fundación Fuentes Abiertas (see README for details)
  4. * This file is part of Goteo.
  5. *
  6. * Goteo is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Goteo is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with Goteo. If not, see <http://www.gnu.org/licenses/agpl.txt>.
  18. *
  19. */
  20. namespace Goteo\Model {
  21. use Goteo\Core\Redirection,
  22. Goteo\Library\Text,
  23. Goteo\Model\Image,
  24. Goteo\Library\Template,
  25. Goteo\Library\Mail,
  26. Goteo\Library\Check,
  27. Goteo\Library\Message;
  28. class User extends \Goteo\Core\Model {
  29. public
  30. $id = false,
  31. $userid, // para el login name al registrarse
  32. $email,
  33. $password, // para gestion de super admin
  34. $name,
  35. $location,
  36. $avatar = false,
  37. $about,
  38. $contribution,
  39. $keywords,
  40. $active, // si no activo, no puede loguear
  41. $confirmed, // si no ha confirmado el email
  42. $hide, // si oculto no aparece su avatar en ninguna parte (pero sus aportes cuentan)
  43. $facebook,
  44. $google,
  45. $twitter,
  46. $identica,
  47. $linkedin,
  48. $created,
  49. $modified,
  50. $interests = array(),
  51. $webs = array(),
  52. $roles = array();
  53. /**
  54. * Sobrecarga de métodos 'setter'.
  55. *
  56. * @param type string $name
  57. * @param type string $value
  58. */
  59. public function __set ($name, $value) {
  60. if($name == "token") {
  61. $this->$name = $this->setToken($value);
  62. }
  63. $this->$name = $value;
  64. }
  65. /**
  66. * Sobrecarga de métodos 'getter'.
  67. *
  68. * @param type string $name
  69. * @return type mixed
  70. */
  71. public function __get ($name) {
  72. if($name == "token") {
  73. return $this->getToken();
  74. }
  75. if($name == "support") {
  76. return $this->getSupport();
  77. }
  78. if($name == "worth") {
  79. return $this->getWorth();
  80. }
  81. return $this->$name;
  82. }
  83. /**
  84. * Guardar usuario.
  85. * Guarda los valores de la instancia del usuario en la tabla.
  86. *
  87. * @param type array $errors Errores devueltos pasados por referencia.
  88. * @param type array $skip_validations Crea el usuario aunque estos campos no sean correctos
  89. * password, active
  90. * @return type bool true|false
  91. */
  92. public function save (&$errors = array(),$skip_validations = array()) {
  93. if($this->validate($errors,$skip_validations)) {
  94. // Nuevo usuario.
  95. if(empty($this->id)) {
  96. $insert = true;
  97. $data[':id'] = $this->id = static::idealiza($this->userid);
  98. $data[':name'] = $this->name;
  99. $data[':location'] = $this->location;
  100. $data[':email'] = $this->email;
  101. $data[':token'] = $token = md5(uniqid());
  102. if(!in_array('password',$skip_validations)) $data[':password'] = sha1($this->password);
  103. $data[':created'] = date('Y-m-d H:i:s');
  104. $data[':active'] = true;
  105. $data[':confirmed'] = false;
  106. // Rol por defecto.
  107. if (!empty($this->id)) {
  108. static::query('REPLACE INTO user_role (user_id, role_id, node_id) VALUES (:user, :role, :node);', array(
  109. ':user' => $this->id,
  110. ':role' => 'user',
  111. ':node' => '*',
  112. ));
  113. }
  114. //active = 1 si no se quiere comprovar
  115. if(in_array('active',$skip_validations) && $this->active) $data[':active'] = 1;
  116. else {
  117. // Obtenemos la plantilla para asunto y contenido
  118. $template = Template::get(5);
  119. // Sustituimos los datos
  120. $subject = $template->title;
  121. // En el contenido:
  122. $search = array('%USERNAME%', '%USERID%', '%ACTIVATEURL%');
  123. $replace = array($this->name, $this->id, SITE_URL . '/user/activate/' . $token);
  124. $content = \str_replace($search, $replace, $template->text);
  125. // Activación
  126. $mail = new Mail();
  127. $mail->to = $this->email;
  128. $mail->toName = $this->name;
  129. $mail->subject = $subject;
  130. $mail->content = $content;
  131. $mail->html = false;
  132. $mail->template = $template->id;
  133. if ($mail->send($errors)) {
  134. Message::Info(Text::get('register-confirm_mail-success'));
  135. } else {
  136. Message::Error(Text::get('register-confirm_mail-fail', GOTEO_MAIL));
  137. Message::Error(implode('<br />', $errors));
  138. }
  139. }
  140. }
  141. else {
  142. $data[':id'] = $this->id;
  143. // E-mail
  144. if(!empty($this->email)) {
  145. if(count($tmp = explode('¬', $this->email)) > 1) {
  146. $data[':email'] = $tmp[1];
  147. $data[':token'] = null;
  148. }
  149. else {
  150. $query = self::query('SELECT email FROM user WHERE id = ?', array($this->id));
  151. if($this->email !== $query->fetchColumn()) {
  152. $this->token = md5(uniqid()) . '¬' . $this->email;
  153. }
  154. }
  155. }
  156. // Contraseña
  157. if(!empty($this->password)) {
  158. $data[':password'] = sha1($this->password);
  159. static::query('DELETE FROM user_login WHERE user= ?', $this->id);
  160. }
  161. if(!is_null($this->active)) {
  162. $data[':active'] = $this->active;
  163. }
  164. if(!is_null($this->confirmed)) {
  165. $data[':confirmed'] = $this->confirmed;
  166. }
  167. if(!is_null($this->hide)) {
  168. $data[':hide'] = $this->hide;
  169. }
  170. // Avatar
  171. if (is_array($this->avatar) && !empty($this->avatar['name'])) {
  172. $image = new Image($this->avatar);
  173. $image->save();
  174. $data[':avatar'] = $image->id;
  175. /**
  176. * Guarda la relación NM en la tabla 'user_image'.
  177. */
  178. if(!empty($image->id)) {
  179. self::query("REPLACE user_image (user, image) VALUES (:user, :image)", array(':user' => $this->id, ':image' => $image->id));
  180. }
  181. }
  182. // Perfil público
  183. if(isset($this->name)) {
  184. $data[':name'] = $this->name;
  185. }
  186. // Dónde está
  187. if(isset($this->location)) {
  188. $data[':location'] = $this->location;
  189. }
  190. if(isset($this->about)) {
  191. $data[':about'] = $this->about;
  192. }
  193. if(isset($this->keywords)) {
  194. $data[':keywords'] = $this->keywords;
  195. }
  196. if(isset($this->contribution)) {
  197. $data[':contribution'] = $this->contribution;
  198. }
  199. if(isset($this->facebook)) {
  200. $data[':facebook'] = $this->facebook;
  201. }
  202. if(isset($this->google)) {
  203. $data[':google'] = $this->google;
  204. }
  205. if(isset($this->twitter)) {
  206. $data[':twitter'] = $this->twitter;
  207. }
  208. if(isset($this->identica)) {
  209. $data[':identica'] = $this->identica;
  210. }
  211. if(isset($this->linkedin)) {
  212. $data[':linkedin'] = $this->linkedin;
  213. }
  214. // Intereses
  215. $interests = User\Interest::get($this->id);
  216. if(!empty($this->interests)) {
  217. foreach($this->interests as $interest) {
  218. if(!in_array($interest, $interests)) {
  219. $_interest = new User\Interest();
  220. $_interest->id = $interest;
  221. $_interest->user = $this->id;
  222. $_interest->save($errors);
  223. $interests[] = $_interest;
  224. }
  225. }
  226. }
  227. foreach($interests as $key => $interest) {
  228. if(!in_array($interest, $this->interests)) {
  229. $_interest = new User\Interest();
  230. $_interest->id = $interest;
  231. $_interest->user = $this->id;
  232. $_interest->remove($errors);
  233. }
  234. }
  235. // Webs
  236. static::query('DELETE FROM user_web WHERE user= ?', $this->id);
  237. if (!empty($this->webs)) {
  238. foreach ($this->webs as $web) {
  239. if ($web instanceof User\Web) {
  240. $web->user = $this->id;
  241. $web->save($errors);
  242. }
  243. }
  244. }
  245. }
  246. try {
  247. // Construye SQL.
  248. if(isset($insert) && $insert == true) {
  249. $query = "INSERT INTO user (";
  250. foreach($data AS $key => $row) {
  251. $query .= substr($key, 1) . ", ";
  252. }
  253. $query = substr($query, 0, -2) . ") VALUES (";
  254. foreach($data AS $key => $row) {
  255. $query .= $key . ", ";
  256. }
  257. $query = substr($query, 0, -2) . ")";
  258. }
  259. else {
  260. $query = "UPDATE user SET ";
  261. foreach($data AS $key => $row) {
  262. if($key != ":id") {
  263. $query .= substr($key, 1) . " = " . $key . ", ";
  264. }
  265. }
  266. $query = substr($query, 0, -2) . " WHERE id = :id";
  267. }
  268. // Ejecuta SQL.
  269. return self::query($query, $data);
  270. } catch(\PDOException $e) {
  271. $errors[] = "Error al actualizar los datos del usuario: " . $e->getMessage();
  272. return false;
  273. }
  274. }
  275. return false;
  276. }
  277. public function saveLang (&$errors = array()) {
  278. $fields = array(
  279. 'id'=>'id',
  280. 'lang'=>'lang',
  281. 'about'=>'about_lang',
  282. 'keywords'=>'keywords_lang',
  283. 'contribution'=>'contribution_lang'
  284. );
  285. $set = '';
  286. $values = array();
  287. foreach ($fields as $field=>$ffield) {
  288. if ($set != '') $set .= ", ";
  289. $set .= "`$field` = :$field ";
  290. $values[":$field"] = $this->$ffield;
  291. }
  292. try {
  293. $sql = "REPLACE INTO user_lang SET " . $set;
  294. self::query($sql, $values);
  295. return true;
  296. } catch(\PDOException $e) {
  297. $errors[] = "El usuario {$this->id} no se ha grabado correctamente. Por favor, revise los datos." . $e->getMessage();
  298. return false;
  299. }
  300. }
  301. /**
  302. * Validación de datos de usuario.
  303. *
  304. * @param type array $errors Errores devueltos pasados por referencia.
  305. * @param type array $skip_validations Crea el usuario aunque estos campos no sean correctos
  306. * password, active
  307. * @return bool true|false
  308. */
  309. public function validate (&$errors = array(), $skip_validations = array()) {
  310. // Nuevo usuario.
  311. if(empty($this->id)) {
  312. // Nombre de usuario (id)
  313. if(empty($this->userid)) {
  314. $errors['userid'] = Text::get('error-register-userid');
  315. }
  316. else {
  317. $id = self::idealiza($this->userid);
  318. $query = self::query('SELECT id FROM user WHERE id = ?', array($id));
  319. if($query->fetchColumn()) {
  320. $errors['userid'] = Text::get('error-register-user-exists');
  321. }
  322. }
  323. if(empty($this->name)) {
  324. $errors['username'] = Text::get('error-register-username');
  325. }
  326. // E-mail
  327. if (empty($this->email)) {
  328. $errors['email'] = Text::get('mandatory-register-field-email');
  329. } elseif (!Check::mail($this->email)) {
  330. $errors['email'] = Text::get('validate-register-value-email');
  331. } else {
  332. $query = self::query('SELECT email FROM user WHERE email = ?', array($this->email));
  333. if($query->fetchObject()) {
  334. $errors['email'] = Text::get('error-register-email-exists');
  335. }
  336. }
  337. // Contraseña
  338. if(!in_array('password',$skip_validations)) {
  339. if(!empty($this->password)) {
  340. if(!Check::password($this->password)) {
  341. $errors['password'] = Text::get('error-register-invalid-password');
  342. }
  343. }
  344. else {
  345. $errors['password'] = Text::get('error-register-pasword-empty');
  346. }
  347. }
  348. return empty($errors);
  349. }
  350. // Modificar usuario.
  351. else {
  352. if(!empty($this->email)) {
  353. if(count($tmp = explode('¬', $this->email)) > 1) {
  354. if($this->email !== $this->token) {
  355. $errors['email'] = Text::get('error-user-email-token-invalid');
  356. }
  357. }
  358. elseif(!Check::mail($this->email)) {
  359. $errors['email'] = Text::get('error-user-email-invalid');
  360. }
  361. else {
  362. $query = self::query('SELECT id FROM user WHERE email = ?', array($this->email));
  363. if($found = $query->fetchColumn()) {
  364. if($this->id !== $found) {
  365. $errors['email'] = Text::get('error-user-email-exists');
  366. }
  367. }
  368. }
  369. }
  370. if(!empty($this->password)) {
  371. if(!Check::password($this->password)) {
  372. $errors['password'] = Text::get('error-user-password-invalid');
  373. }
  374. }
  375. if (is_array($this->avatar) && !empty($this->avatar['name'])) {
  376. $image = new Image($this->avatar);
  377. $_err = array();
  378. $image->validate($_err);
  379. $errors['avatar'] = $_err['image'];
  380. }
  381. }
  382. if (\str_replace(Text::get('regular-facebook-url'), '', $this->facebook) == '') $this->facebook = '';
  383. if (\str_replace(Text::get('regular-google-url'), '', $this->google) == '') $this->google = '';
  384. if (\str_replace(Text::get('regular-twitter-url'), '', $this->twitter) == '') $this->twitter = '';
  385. if (\str_replace(Text::get('regular-identica-url'), '', $this->identica) == '') $this->identica = '';
  386. if (\str_replace(Text::get('regular-linkedin-url'), '', $this->linkedin) == '') $this->linkedin = '';
  387. return (empty($errors['email']) && empty($errors['password']));
  388. }
  389. /**
  390. * Este método actualiza directamente los campos de email y contraseña de un usuario (para gestión de superadmin)
  391. */
  392. public function update (&$errors = array()) {
  393. if(!empty($this->password)) {
  394. if(!Check::password($this->password)) {
  395. $errors['password'] = Text::get('error-user-password-invalid');
  396. }
  397. }
  398. if(!empty($this->email)) {
  399. if(!Check::mail($this->email)) {
  400. $errors['email'] = Text::get('error-user-email-invalid');
  401. }
  402. else {
  403. $query = self::query('SELECT id FROM user WHERE email = ?', array($this->email));
  404. if($found = $query->fetchColumn()) {
  405. if($this->id !== $found) {
  406. $errors['email'] = Text::get('error-user-email-exists');
  407. }
  408. }
  409. }
  410. }
  411. if (!empty($errors['email']) || !empty($errors['password'])) {
  412. return false;
  413. }
  414. $set = '';
  415. $values = array(':id'=>$this->id);
  416. if (!empty($this->email)) {
  417. if ($set != '') $set .= ", ";
  418. $set .= "`email` = :email ";
  419. $values[":email"] = $this->email;
  420. }
  421. if (!empty($this->password)) {
  422. if ($set != '') $set .= ", ";
  423. $set .= "`password` = :password ";
  424. $values[":password"] = sha1($this->password);
  425. }
  426. if ($set == '') return false;
  427. try {
  428. $sql = "UPDATE user SET " . $set . " WHERE id = :id";
  429. self::query($sql, $values);
  430. return true;
  431. } catch(\PDOException $e) {
  432. $errors[] = "No se ha guardado correctamente. " . $e->getMessage();
  433. return false;
  434. }
  435. }
  436. /**
  437. * Usuario.
  438. *
  439. * @param string $id Nombre de usuario
  440. * @return obj|false Objeto de usuario, en caso contrario devolverá 'false'.
  441. */
  442. public static function get ($id, $lang = null) {
  443. try {
  444. if (!$lang == 'es') $lang = null;
  445. $sql = "
  446. SELECT
  447. user.id as id,
  448. user.email as email,
  449. user.name as name,
  450. user.location as location,
  451. user.avatar as avatar,
  452. IFNULL(user_lang.about, user.about) as about,
  453. IFNULL(user_lang.contribution, user.contribution) as contribution,
  454. IFNULL(user_lang.keywords, user.keywords) as keywords,
  455. user.facebook as facebook,
  456. user.google as google,
  457. user.twitter as twitter,
  458. user.identica as identica,
  459. user.linkedin as linkedin,
  460. user.active as active,
  461. user.confirmed as confirmed,
  462. user.hide as hide,
  463. user.created as created,
  464. user.modified as modified
  465. FROM user
  466. LEFT JOIN user_lang
  467. ON user_lang.id = user.id
  468. AND user_lang.lang = :lang
  469. WHERE user.id = :id
  470. ";
  471. $query = static::query($sql, array(':id' => $id, ':lang' => $lang));
  472. $user = $query->fetchObject(__CLASS__);
  473. if (!$user instanceof \Goteo\Model\User) {
  474. throw new \Goteo\Core\Error('404', Text::html('fatal-error-user'));
  475. }
  476. $user->roles = $user->getRoles();
  477. $user->avatar = Image::get($user->avatar);
  478. if (empty($user->avatar->id) || !$user->avatar instanceof Image) {
  479. $user->avatar = Image::get(1);
  480. }
  481. $user->interests = User\Interest::get($id);
  482. $user->webs = User\Web::get($id);
  483. return $user;
  484. } catch(\PDOException $e) {
  485. return false;
  486. }
  487. }
  488. // version mini de get para sacar nombre i mail
  489. public static function getMini ($id) {
  490. try {
  491. $query = static::query("
  492. SELECT
  493. id,
  494. name,
  495. avatar,
  496. email
  497. FROM user
  498. WHERE id = :id
  499. ", array(':id' => $id));
  500. $user = $query->fetchObject(); // stdClass para qno grabar accidentalmente y machacar todo
  501. $user->avatar = Image::get($user->avatar);
  502. if (empty($user->avatar->id) || !$user->avatar instanceof Image) {
  503. $user->avatar = Image::get(1);
  504. }
  505. return $user;
  506. } catch(\PDOException $e) {
  507. return false;
  508. }
  509. }
  510. /**
  511. * Lista de usuarios.
  512. *
  513. * @param bool $visible true|false
  514. * @return mixed Array de objetos de usuario activos|todos.
  515. */
  516. public static function getAll ($filters = array()) {
  517. $users = array();
  518. $sqlFilter = "";
  519. if (!empty($filters['name'])) {
  520. $sqlFilter .= " AND ( name LIKE ('%{$filters['name']}%') OR email LIKE ('%{$filters['name']}%') )";
  521. }
  522. if (!empty($filters['status'])) {
  523. $active = $filters['status'] == 'active' ? '1' : '0';
  524. $sqlFilter .= " AND active = '$active'";
  525. }
  526. if (!empty($filters['interest'])) {
  527. $sqlFilter .= " AND id IN (
  528. SELECT user
  529. FROM user_interest
  530. WHERE interest = {$filters['interest']}
  531. ) ";
  532. }
  533. if (!empty($filters['role'])) {
  534. $sqlFilter .= " AND id IN (
  535. SELECT user_id
  536. FROM user_role
  537. WHERE role_id = '{$filters['role']}'
  538. ) ";
  539. }
  540. if (!empty($filters['posted'])) {
  541. /*
  542. * Si ha enviado algun mensaje o comentario
  543. $sqlFilter .= " AND id IN (
  544. SELECT user
  545. FROM message
  546. WHERE interest = {$filters['interest']}
  547. ) ";
  548. *
  549. */
  550. }
  551. //el Order
  552. switch ($filters['order']) {
  553. case 'name':
  554. $sqlOrder .= " ORDER BY name ASC";
  555. break;
  556. default:
  557. $sqlOrder .= " ORDER BY created DESC";
  558. break;
  559. }
  560. $sql = "SELECT
  561. id,
  562. name,
  563. email,
  564. active,
  565. hide,
  566. DATE_FORMAT(created, '%d/%m/%Y %H:%i:%s') as register_date
  567. FROM user
  568. WHERE id != 'root'
  569. $sqlFilter
  570. $sqlOrder
  571. ";
  572. $query = self::query($sql, array($node));
  573. foreach ($query->fetchAll(\PDO::FETCH_CLASS, __CLASS__) as $user) {
  574. $query = static::query("
  575. SELECT
  576. role_id
  577. FROM user_role
  578. WHERE user_id = :id
  579. ", array(':id' => $user->id));
  580. foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $role) {
  581. if ($role->role_id == 'checker') {
  582. $user->checker = true;
  583. }
  584. if ($role->role_id == 'translator') {
  585. $user->translator = true;
  586. }
  587. if ($role->role_id == 'admin') {
  588. $user->admin = true;
  589. }
  590. }
  591. $users[] = $user;
  592. }
  593. return $users;
  594. }
  595. /*
  596. * Listado simple de todos los usuarios
  597. */
  598. public static function getAllMini() {
  599. $list = array();
  600. $query = static::query("
  601. SELECT
  602. user.id as id,
  603. user.name as name
  604. FROM user
  605. ORDER BY user.name ASC
  606. ");
  607. foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $item) {
  608. $list[$item->id] = $item->name;
  609. }
  610. return $list;
  611. }
  612. /*
  613. * Listado simple de los usuarios que han creado proyectos
  614. */
  615. public static function getOwners() {
  616. $list = array();
  617. $query = static::query("
  618. SELECT
  619. user.id as id,
  620. user.name as name
  621. FROM user
  622. INNER JOIN project
  623. ON project.owner = user.id
  624. ORDER BY user.name ASC
  625. ");
  626. foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $item) {
  627. $list[$item->id] = $item->name;
  628. }
  629. return $list;
  630. }
  631. /*
  632. * Listado id-nombre-email de los usuarios que siguen teniendo su email como contraseña
  633. public static function getWorkshoppers() {
  634. $list = array();
  635. $query = static::query("
  636. SELECT
  637. user.id as id,
  638. user.name as name,
  639. user.email as email
  640. FROM user
  641. WHERE BINARY password = SHA1(user.email)
  642. ORDER BY user.name ASC
  643. ");
  644. foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $item) {
  645. $list[] = $item;
  646. }
  647. return $list;
  648. }
  649. */
  650. /**
  651. * Validación de usuario.
  652. *
  653. * @param string $username Nombre de usuario
  654. * @param string $password Contraseña
  655. * @return obj|false Objeto del usuario, en caso contrario devolverá 'false'.
  656. */
  657. public static function login ($username, $password) {
  658. $query = self::query("
  659. SELECT
  660. id
  661. FROM user
  662. WHERE BINARY id = :username
  663. AND BINARY password = :password",
  664. array(
  665. ':username' => trim($username),
  666. ':password' => sha1($password)
  667. )
  668. );
  669. if($row = $query->fetch()) {
  670. $user = static::get($row['id']);
  671. if($user->active) {
  672. return $user;
  673. } else {
  674. Message::Error(Text::get('user-account-inactive'));
  675. }
  676. }
  677. return false;
  678. }
  679. /**
  680. * Comprueba si el usuario está identificado.
  681. *
  682. * @return boolean
  683. */
  684. public static function isLogged () {
  685. return !empty($_SESSION['user']);
  686. }
  687. /**
  688. * Refresca la sesión.
  689. * (Utilizar después de un save)
  690. *
  691. * @return type object User
  692. */
  693. public static function flush () {
  694. if(static::isLogged()) {
  695. return $_SESSION['user'] = self::get($_SESSION['user']->id);
  696. }
  697. }
  698. /**
  699. * Verificacion de recuperacion de contraseña
  700. *
  701. * @param string $username Nombre de usuario
  702. * @param string $email Email de la cuenta
  703. * @return boolean true|false Correctos y mail enviado
  704. */
  705. public static function recover ($username = null, $email = null) {
  706. $query = self::query("
  707. SELECT
  708. id,
  709. name,
  710. email
  711. FROM user
  712. WHERE (BINARY id = :username
  713. OR BINARY email = :email)
  714. ",
  715. array(
  716. ':username' => trim($username),
  717. ':email' => trim($email)
  718. )
  719. );
  720. if($row = $query->fetchObject()) {
  721. // tenemos id, nombre, email
  722. // genero el token
  723. $token = md5(uniqid()) . '¬' . $row->email;
  724. self::query('UPDATE user SET token = :token WHERE id = :id', array(':id' => $row->id, ':token' => $token));
  725. // Obtenemos la plantilla para asunto y contenido
  726. $template = Template::get(6);
  727. // Sustituimos los datos
  728. $subject = $template->title;
  729. // En el contenido:
  730. $search = array('%USERNAME%', '%USERID%', '%RECOVERURL%');
  731. $replace = array($row->name, $row->id, SITE_URL . '/user/recover/' . base64_encode($token));
  732. $content = \str_replace($search, $replace, $template->text);
  733. // Email de recuperacion
  734. $mail = new Mail();
  735. $mail->to = $row->email;
  736. $mail->toName = $row->name;
  737. $mail->subject = $subject;
  738. $mail->content = $content;
  739. $mail->html = true;
  740. $mail->template = $template->id;
  741. if ($mail->send($errors)) {
  742. return true;
  743. }
  744. }
  745. return false;
  746. }
  747. /**
  748. * Verificacion de darse de baja
  749. *
  750. * @param string $email Email de la cuenta
  751. * @return boolean true|false Correctos y mail enviado
  752. */
  753. public static function leaving ($email, $message = null) {
  754. $query = self::query("
  755. SELECT
  756. id,
  757. name,
  758. email
  759. FROM user
  760. WHERE BINARY email = :email
  761. AND active = 1
  762. AND hide = 0
  763. ",
  764. array(
  765. ':email' => trim($email)
  766. )
  767. );
  768. if($row = $query->fetchObject()) {
  769. // tenemos id, nombre, email
  770. // genero el token
  771. $token = md5(uniqid()) . '¬' . $row->email;
  772. self::query('UPDATE user SET token = :token WHERE id = :id', array(':id' => $row->id, ':token' => $token));
  773. // Obtenemos la plantilla para asunto y contenido
  774. $template = Template::get(9);
  775. // Sustituimos los datos
  776. $subject = $template->title;
  777. // En el contenido:
  778. $search = array('%USERNAME%', '%URL%');
  779. $replace = array($row->name, SITE_URL . '/user/leave/' . base64_encode($token));
  780. $content = \str_replace($search, $replace, $template->text);
  781. // Email de recuperacion
  782. $mail = new Mail();
  783. $mail->to = $row->email;
  784. $mail->toName = $row->name;
  785. $mail->subject = $subject;
  786. $mail->content = $content;
  787. $mail->html = true;
  788. $mail->template = $template->id;
  789. $mail->send($errors);
  790. unset($mail);
  791. // email a los de goteo
  792. $mail = new Mail();
  793. $mail->to = \GOTEO_MAIL;
  794. $mail->toName = 'Admin Goteo';
  795. $mail->subject = 'El usuario ' . $row->id . ' se da de baja';
  796. $mail->content = '<p>Han solicitado la baja para el mail <strong>'.$email.'</strong> que corresponde al usuario <strong>'.$row->name.'</strong>';
  797. if (!empty($message)) $mail->content .= 'y ha dejado el siguiente mensaje:</p><p> ' . $message;
  798. $mail->content .= '</p>';
  799. $mail->fromName = "{$row->name}";
  800. $mail->from = $row->email;
  801. $mail->html = true;
  802. $mail->template = 0;
  803. $mail->send($errors);
  804. unset($mail);
  805. return true;
  806. }
  807. return false;
  808. }
  809. /**
  810. * Guarda el Token y envía un correo de confirmación.
  811. *
  812. * Usa el separador: ¬
  813. *
  814. * @param type string $token Formato: '<md5>¬<email>'
  815. * @return type bool
  816. */
  817. private function setToken ($token) {
  818. if(count($tmp = explode('¬', $token)) > 1) {
  819. $email = $tmp[1];
  820. if(Check::mail($email)) {
  821. // Obtenemos la plantilla para asunto y contenido
  822. $template = Template::get(7);
  823. // Sustituimos los datos
  824. $subject = $template->title;
  825. // En el contenido:
  826. $search = array('%USERNAME%', '%CHANGEURL%');
  827. $replace = array($this->name, SITE_URL . '/user/changeemail/' . base64_encode($token));
  828. $content = \str_replace($search, $replace, $template->text);
  829. $mail = new Mail();
  830. $mail->to = $email;
  831. $mail->toName = $this->name;
  832. $mail->subject = $subject;
  833. $mail->content = $content;
  834. $mail->html = true;
  835. $mail->template = $template->id;
  836. $mail->send();
  837. return self::query('UPDATE user SET token = :token WHERE id = :id', array(':id' => $this->id, ':token' => $token));
  838. }
  839. }
  840. }
  841. /**
  842. * Token de confirmación.
  843. *
  844. * @return type string
  845. */
  846. private function getToken () {
  847. $query = self::query('SELECT token FROM user WHERE id = ?', array($this->id));
  848. return $query->fetchColumn(0);
  849. }
  850. /**
  851. * Cofinanciación.
  852. *
  853. * @return type array
  854. */
  855. private function getSupport () {
  856. $query = self::query('SELECT DISTINCT(project) FROM invest WHERE user = ? AND (status = 0 OR status = 1 OR status = 3 OR status = 4)', array($this->id));
  857. $projects = $query->fetchAll(\PDO::FETCH_ASSOC);
  858. $query = self::query('SELECT SUM(amount), COUNT(id) FROM invest WHERE user = ? AND (status = 0 OR status = 1 OR status = 3 OR status = 4)', array($this->id));
  859. $invest = $query->fetch();
  860. return array('projects' => $projects, 'amount' => $invest[0], 'invests' => $invest[1]);
  861. }
  862. /**
  863. * Nivel actual de meritocracia. (1-5)
  864. * [Recalcula y actualiza el registro en db]
  865. *
  866. * @return type int Worth::id
  867. */
  868. private function getWorth () {
  869. $query = self::query('SELECT id FROM worthcracy WHERE amount <= ? ORDER BY amount DESC LIMIT 1', array($this->support['amount']));
  870. $worth = $query->fetchColumn();
  871. $query = self::query('SELECT worth FROM user WHERE id = ?', array($this->id));
  872. if($worth !== $query->fetchColumn()) {
  873. self::query('UPDATE user SET worth = :worth WHERE id = :id', array(':id' => $this->id, ':worth' => $worth));
  874. }
  875. return $worth;
  876. }
  877. /**
  878. * Valores por defecto actuales para datos personales
  879. *
  880. * @return type array
  881. */
  882. public static function getPersonal ($id) {
  883. $query = self::query('SELECT
  884. contract_name,
  885. contract_nif,
  886. phone,
  887. address,
  888. zipcode,
  889. location,
  890. country
  891. FROM user_personal
  892. WHERE user = ?'
  893. , array($id));
  894. $data = $query->fetchObject();
  895. return $data;
  896. }
  897. /**
  898. * Actualizar los valores personales
  899. *
  900. * @params force boolean (REPLACE data when true, only if empty when false)
  901. * @return type booblean
  902. */
  903. public static function setPersonal ($user, $data = array(), $force = false, &$errors = array()) {
  904. if ($force) {
  905. // actualizamos los datos
  906. $ins = 'REPLACE';
  907. } else {
  908. // solo si no existe el registro
  909. $ins = 'INSERT';
  910. $query = self::query('SELECT user FROM user_personal WHERE user = ?', array($user));
  911. if ($query->fetchColumn(0) == $user) {
  912. return false;
  913. }
  914. }
  915. $fields = array(
  916. 'contract_name',
  917. 'contract_nif',
  918. 'phone',
  919. 'address',
  920. 'zipcode',
  921. 'location',
  922. 'country'
  923. );
  924. $values = array();
  925. $set = '';
  926. foreach ($data as $key=>$value) {
  927. if (in_array($key, $fields)) {
  928. $values[":$key"] = $value;
  929. if ($set != '') $set .= ', ';
  930. $set .= "$key = :$key";
  931. }
  932. }
  933. if (!empty($values) && $set != '') {
  934. $values[':user'] = $user;
  935. $sql = "$ins INTO user_personal SET user = :user, " . $set;
  936. try {
  937. self::query($sql, $values);
  938. return true;
  939. } catch (\PDOException $e) {
  940. $errors[] = "FALLO al gestionar el registro de datos personales " . $e->getMessage();
  941. return false;
  942. }
  943. }
  944. }
  945. /**
  946. * Preferencias de notificacion
  947. *
  948. * @return type array
  949. */
  950. public static function getPreferences ($id) {
  951. $query = self::query('SELECT
  952. updates,
  953. threads,
  954. rounds,
  955. mailing
  956. FROM user_prefer
  957. WHERE user = ?'
  958. , array($id));
  959. $data = $query->fetchObject();
  960. return $data;
  961. }
  962. /**
  963. * Actualizar las preferencias de notificación
  964. *
  965. * @return type booblean
  966. */
  967. public static function setPreferences ($user, $data = array(), &$errors = array()) {
  968. $values = array();
  969. $set = '';
  970. foreach ($data as $key=>$value) {
  971. $values[":$key"] = $value;
  972. if ($set != '') $set .= ', ';
  973. $set .= "$key = :$key";
  974. }
  975. if (!empty($values) && $set != '') {
  976. $values[':user'] = $user;
  977. $sql = "REPLACE INTO user_prefer SET user = :user, " . $set;
  978. try {
  979. self::query($sql, $values);
  980. return true;
  981. } catch (\PDOException $e) {
  982. $errors[] = "FALLO al gestionar las preferencias de notificación " . $e->getMessage();
  983. return false;
  984. }
  985. }
  986. }
  987. private function getRoles () {
  988. $roles = array();
  989. $query = self::query('
  990. SELECT
  991. role.id as id,
  992. role.name as name
  993. FROM role
  994. JOIN user_role ON role.id = user_role.role_id
  995. WHERE user_id = ?
  996. ', array($this->id));
  997. foreach ($query->fetchAll(\PDO::FETCH_OBJ) as $rol) {
  998. $roles[$rol->id] = $rol;
  999. }
  1000. return $roles;
  1001. }
  1002. /*
  1003. * Lista de proyectos cofinanciados
  1004. */
  1005. public static function invested($user, $publicOnly = true)
  1006. {
  1007. $projects = array();
  1008. $sql = "SELECT project.id
  1009. FROM project
  1010. INNER JOIN invest
  1011. ON project.id = invest.project
  1012. AND invest.user = ?
  1013. AND (invest.status = 0 OR invest.status = 1)
  1014. WHERE project.status < 7
  1015. ";
  1016. if ($publicOnly) {
  1017. $sql .= "AND project.status >= 3
  1018. ";
  1019. }
  1020. $sql .= "GROUP BY project.id
  1021. ORDER BY name ASC
  1022. ";
  1023. /*
  1024. * Restriccion de que no aparecen los que cofinancio que esten en edicion
  1025. * solamente no sacamos los caducados
  1026. * project.status > 1 AND
  1027. */
  1028. $query = self::query($sql, array($user));
  1029. foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $proj) {
  1030. $projects[] = \Goteo\Model\Project::get($proj->id);
  1031. }
  1032. return $projects;
  1033. }
  1034. public static function calcWorth($userId) {
  1035. $query = self::query('SELECT id FROM worthcracy WHERE amount <= (SELECT SUM(amount) FROM invest WHERE user = ? AND (status = 0 OR status = 1)) ORDER BY amount DESC LIMIT 1', array($userId));
  1036. $worth = $query->fetchColumn();
  1037. self::query('UPDATE user SET worth = :worth WHERE id = :id', array(':id' => $userId, ':worth' => $worth));
  1038. return $worth;
  1039. }
  1040. /**
  1041. * Metodo para cancelar la cuenta de usuario
  1042. * Nos e borra nada, se desactiva y se oculta.
  1043. *
  1044. * @param string $userId
  1045. * @return bool
  1046. */
  1047. public static function cancel($userId) {
  1048. if (self::query('UPDATE user SET active = 0, hide = 1 WHERE id = :id', array(':id' => $userId))) {
  1049. return true;
  1050. } else {
  1051. return false;
  1052. }
  1053. }
  1054. }
  1055. }