You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

744 line
26KB

  1. <?php
  2. /**
  3. * Copyright distrib (2018)
  4. *
  5. * contact@opendistrib.net
  6. *
  7. * Ce logiciel est un programme informatique servant à aider les producteurs
  8. * à distribuer leur production en circuits courts.
  9. *
  10. * Ce logiciel est régi par la licence CeCILL soumise au droit français et
  11. * respectant les principes de diffusion des logiciels libres. Vous pouvez
  12. * utiliser, modifier et/ou redistribuer ce programme sous les conditions
  13. * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
  14. * sur le site "http://www.cecill.info".
  15. *
  16. * En contrepartie de l'accessibilité au code source et des droits de copie,
  17. * de modification et de redistribution accordés par cette licence, il n'est
  18. * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
  19. * seule une responsabilité restreinte pèse sur l'auteur du programme, le
  20. * titulaire des droits patrimoniaux et les concédants successifs.
  21. *
  22. * A cet égard l'attention de l'utilisateur est attirée sur les risques
  23. * associés au chargement, à l'utilisation, à la modification et/ou au
  24. * développement et à la reproduction du logiciel par l'utilisateur étant
  25. * donné sa spécificité de logiciel libre, qui peut le rendre complexe à
  26. * manipuler et qui le réserve donc à des développeurs et des professionnels
  27. * avertis possédant des connaissances informatiques approfondies. Les
  28. * utilisateurs sont donc invités à charger et tester l'adéquation du
  29. * logiciel à leurs besoins dans des conditions permettant d'assurer la
  30. * sécurité de leurs systèmes et ou de leurs données et, plus généralement,
  31. * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
  32. *
  33. * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
  34. * pris connaissance de la licence CeCILL, et que vous en avez accepté les
  35. * termes.
  36. */
  37. namespace common\models;
  38. use common\helpers\GlobalParam;
  39. use yii\web\IdentityInterface;
  40. use yii\db\Query;
  41. use common\components\ActiveRecordCommon;
  42. /**
  43. * User model
  44. *
  45. * @property integer $id
  46. * @property string $username
  47. * @property string $password_hash
  48. * @property string $password_reset_token
  49. * @property string $email
  50. * @property string $auth_key
  51. * @property integer $status
  52. * @property integer $created_at
  53. * @property integer $updated_at
  54. * @property string $password write-only password
  55. * @property boolean $confiance
  56. */
  57. class User extends ActiveRecordCommon implements IdentityInterface
  58. {
  59. const TYPE_INDIVIDUAL = 'individual' ;
  60. const TYPE_LEGAL_PERSON = 'legal-person' ;
  61. const STATUS_DELETED = 0;
  62. const STATUS_ACTIVE = 10;
  63. const STATUS_PRODUCER = 11;
  64. const STATUS_ADMIN = 13;
  65. const ID_USER_SYSTEM = 0;
  66. var $password_old;
  67. var $password_new;
  68. var $password_new_confirm;
  69. var $points_sale = [];
  70. var $one_name ;
  71. /**
  72. * @inheritdoc
  73. */
  74. public static function tableName()
  75. {
  76. return '{{%user}}';
  77. }
  78. /**
  79. * @inheritdoc
  80. */
  81. public function behaviors()
  82. {
  83. return [
  84. TimestampBehavior::className(),
  85. ];
  86. }
  87. /**
  88. * @inheritdoc
  89. */
  90. public function rules()
  91. {
  92. return [
  93. [['no_mail', 'mail_distribution_monday', 'mail_distribution_tuesday', 'mail_distribution_wednesday', 'mail_distribution_thursday', 'mail_distribution_friday', 'mail_distribution_saturday', 'mail_distribution_sunday', 'is_main_contact'], 'boolean'],
  94. [['lastname', 'name', 'phone', 'address', 'type', 'name_legal_person'], 'string'],
  95. ['lastname', 'verifyOneName', 'skipOnError' => false, 'skipOnEmpty' => false],
  96. ['email', 'email', 'message' => 'Cette adresse email n\'est pas valide'],
  97. ['email', 'verifyEmail'],
  98. ['status', 'default', 'value' => self::STATUS_ACTIVE],
  99. ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED, self::STATUS_ADMIN, self::STATUS_PRODUCER]],
  100. ['password_old', 'verifyPasswordOld'],
  101. ['password_new', 'verifyPasswordNew'],
  102. ['password_new_confirm', 'verifyPasswordNewConfirm'],
  103. [['date_last_connection', 'password_old', 'password_new', 'password_new_confirm', 'password_hash', 'points_sale'], 'safe'],
  104. ];
  105. }
  106. public function attributeLabels()
  107. {
  108. return [
  109. 'id' => 'ID',
  110. 'name' => 'Prénom',
  111. 'lastname' => 'Nom',
  112. 'phone' => 'Téléphone',
  113. 'address' => 'Adresse',
  114. 'username' => 'Identifiant',
  115. 'password' => 'Mot de passe',
  116. 'rememberMe' => 'Se souvenir de moi',
  117. 'no_mail' => 'Ne pas recevoir d\'email de la part du Chat des Noisettes',
  118. 'mail_distribution_monday' => 'Lundi',
  119. 'mail_distribution_tuesday' => 'Mardi',
  120. 'mail_distribution_wednesday' => 'Mercredi',
  121. 'mail_distribution_thursday' => 'Jeudi',
  122. 'mail_distribution_friday' => 'Vendredi',
  123. 'mail_distribution_saturday' => 'Samedi',
  124. 'mail_distribution_sunday' => 'Dimanche',
  125. 'password_old' => 'Ancien mot de passe',
  126. 'password_new' => 'Nouveau mot de passe',
  127. 'password_new_confirm' => 'Confirmation du nouveau mot de passe',
  128. 'points_sale' => 'Points de vente',
  129. 'type' => 'Type',
  130. 'name_legal_person' => 'Libellé',
  131. 'is_main_contact' => 'Contact principal'
  132. ];
  133. }
  134. /**
  135. * Retourne les options de base nécessaires à la fonction de recherche.
  136. *
  137. * @return array
  138. */
  139. public static function defaultOptionsSearch()
  140. {
  141. return [
  142. 'with' => [],
  143. 'join_with' => ['userProducer'],
  144. 'orderby' => 'user.name ASC, user.lastname ASC',
  145. 'attribute_id_producer' => ''
  146. ];
  147. }
  148. /**
  149. * Vérifie le mot de passe envoyé par l'utilisateur.
  150. *
  151. * @param string $attribute
  152. * @param array $params
  153. */
  154. public function verifyPasswordOld($attribute, $params)
  155. {
  156. if (strlen($this->password_old)) {
  157. if (!$this->validatePassword($this->password_old)) {
  158. $this->addError($attribute, 'Mot de passe invalide.');
  159. }
  160. }
  161. if (!strlen($this->password_old) && (strlen($this->password_new) || strlen($this->password_new_confirm))) {
  162. $this->addError($attribute, 'Ce champs ne peut être vide');
  163. }
  164. if (!strlen($this->password_new) && (strlen($this->password_old) || strlen($this->password_new_confirm))) {
  165. $this->addError('password_new', 'Ce champs ne peut être vide');
  166. }
  167. if (!strlen($this->password_new_confirm) && (strlen($this->password_old) || strlen($this->password_new))) {
  168. $this->addError('password_new_confirm', 'Ce champs ne peut être vide');
  169. }
  170. }
  171. /**
  172. * Vérifie le mot de passe de l'utilisateur.
  173. *
  174. * @param string $attribute
  175. * @param array $params
  176. */
  177. public function verifyPasswordNew($attribute, $params)
  178. {
  179. if (strlen($this->password_new) < 6) {
  180. $this->addError($attribute, 'Votre mot de passe doit comporter au moins 6 caractères.');
  181. }
  182. }
  183. /**
  184. * Vérifie la confirmation de mot de passe de l'utilisateur.
  185. *
  186. * @param string $attribute
  187. * @param array $params
  188. */
  189. public function verifyPasswordNewConfirm($attribute, $params)
  190. {
  191. if ($this->password_new != $this->password_new_confirm) {
  192. $this->addError($attribute, 'Les deux mots de passe doivent être identiques');
  193. }
  194. }
  195. /**
  196. * Vérifie l'email de l'utilisateur.
  197. *
  198. * @param string $attribute
  199. * @param array $params
  200. */
  201. public function verifyEmail($attribute, $params)
  202. {
  203. if($this->id) {
  204. $user = User::find()->where("email LIKE :email AND id != :id")->params(array(':email' => '%' . $this->email . '%', ':id' => $this->id))->one();
  205. }
  206. else {
  207. $user = User::find()->where("email LIKE :email")->params(array(':email' => '%' . $this->email . '%'))->one();
  208. }
  209. if ($user) {
  210. $this->addError($attribute, 'Cette adresse email est déjà utilisée par un autre utilisateur ');
  211. }
  212. }
  213. /**
  214. * Vérifie que l'utilisateur a au moins un nom de défini
  215. *
  216. * @param $attribute
  217. * @param $params
  218. */
  219. public function verifyOneName($attribute, $params)
  220. {
  221. if(strlen($this->lastname) == 0 && strlen($this->name_legal_person) == 0) {
  222. $this->addError('lastname', 'Vous devez saisir au moins un nom.');
  223. $this->addError('name_legal_person', 'Vous devez saisir au moins un nom.');
  224. }
  225. }
  226. /*
  227. * Relations
  228. */
  229. public function getUserProducer()
  230. {
  231. return $this->hasMany(UserProducer::className(), ['id_user' => 'id']);
  232. }
  233. public function getOrder()
  234. {
  235. return $this->hasMany(Order::className(), ['id_user' => 'id']);
  236. }
  237. /**
  238. * @inheritdoc
  239. */
  240. public static function findIdentity($id)
  241. {
  242. return static::findOne(['id' => $id]);
  243. }
  244. /**
  245. * @inheritdoc
  246. */
  247. public static function findIdentityByAccessToken($token, $type = null)
  248. {
  249. throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
  250. }
  251. /**
  252. * Finds user by username
  253. *
  254. * @param string $username
  255. * @return static|null
  256. */
  257. public static function findByUsername($username)
  258. {
  259. return static::findOne(['username' => $username]);
  260. }
  261. /**
  262. * Recherche un utilisateur via son adresse email.
  263. *
  264. * @param string $email
  265. * @return User
  266. */
  267. public static function findByEmail($email)
  268. {
  269. return static::findOne(['email' => $email]);
  270. }
  271. /**
  272. * Finds user by password reset token
  273. *
  274. * @param string $token password reset token
  275. * @return static|null
  276. */
  277. public static function findByPasswordResetToken($token)
  278. {
  279. if (!static::isPasswordResetTokenValid($token)) {
  280. return null;
  281. }
  282. return static::findOne([
  283. 'password_reset_token' => $token,
  284. ]);
  285. }
  286. /**
  287. * Recherche des utilisateurs suivant les paramètres : id_etablissement,
  288. * inactifs, id_point_vente, nom, prenom, email, telephone.
  289. *
  290. * @param array $params
  291. * @return Query
  292. */
  293. public static function findBy($params = [])
  294. {
  295. if (!isset($params['id_producer'])) {
  296. $params['id_producer'] = GlobalParam::getCurrentProducerId();
  297. }
  298. $query = (new Query())
  299. ->select(['user.id AS user_id', 'user.name', 'user.lastname', 'user.phone', 'user.email', 'user.created_at', 'user.date_last_connection', 'user_producer.*', 'user.address', 'user.name_legal_person'])
  300. ->from('user');
  301. $active = (isset($params['inactive']) && $params['inactive']) ? 0 : 1;
  302. $query->innerJoin('user_producer', 'user.id = user_producer.id_user AND user_producer.active = ' . $active . ' AND user_producer.id_producer = :id_producer', [':id_producer' => $params['id_producer']]);
  303. if (isset($params['id_point_sale']) && $params['id_point_sale']) {
  304. $point_sale = PointSale::findOne(['id' => $params['id_point_sale']]);
  305. $conditionLinkUserPointSale = 'user.id = user_point_sale.id_user AND user_point_sale.id_point_sale = :id_point_sale';
  306. $usersPointSaleLink = false;
  307. $usersPointSaleHasOrder = false;
  308. if (isset($params['users_point_sale_link']) && $params['users_point_sale_link']) {
  309. $usersPointSaleLink = true;
  310. } elseif (isset($params['users_point_sale_has_order']) && $params['users_point_sale_has_order']) {
  311. $usersPointSaleHasOrder = true;
  312. } elseif ($point_sale->restricted_access) {
  313. $usersPointSaleLink = true;
  314. } else {
  315. $usersPointSaleHasOrder = true;
  316. }
  317. if ($usersPointSaleLink) {
  318. $query->innerJoin('user_point_sale', 'user.id = user_point_sale.id_user AND user_point_sale.id_point_sale = :id_point_sale', [':id_point_sale' => $params['id_point_sale']]);
  319. } elseif ($usersPointSaleHasOrder) {
  320. $query->innerJoin(
  321. 'order',
  322. 'user.id = order.id_user AND order.id_point_sale = :id_point_sale',
  323. [':id_point_sale' => $params['id_point_sale']]
  324. )->groupBy('user.id');
  325. }
  326. }
  327. if (isset($params['subscribers']) && $params['subscribers']) {
  328. $query->innerJoin(
  329. 'subscription',
  330. 'user.id = subscription.id_user AND subscription.id_producer = :id_producer',
  331. [':id_producer' => GlobalParam::getCurrentProducerId()]
  332. )->groupBy('user.id');
  333. }
  334. if (isset($params['inactive']) && $params['inactive']) {
  335. $query->innerJoin(
  336. 'order',
  337. 'user.id = order.id_user'
  338. )
  339. ->groupBy('user.id');
  340. }
  341. if (isset($params['name'])) {
  342. $query->andFilterWhere(['like', 'name', $params['name']]);
  343. }
  344. if (isset($params['lastname'])) {
  345. $query->andFilterWhere(['like', 'lastname', $params['lastname']]);
  346. }
  347. if (isset($params['email'])) {
  348. $query->andFilterWhere(['like', 'email', $params['email']]);
  349. }
  350. if (isset($params['phone'])) {
  351. $query->andFilterWhere(['like', 'phone', $params['phone']]);
  352. }
  353. $query->orderBy('user.type DESC, user.lastname ASC, user.name ASC');
  354. return $query;
  355. }
  356. /**
  357. * Finds out if password reset token is valid
  358. *
  359. * @param string $token password reset token
  360. * @return boolean
  361. */
  362. public static function isPasswordResetTokenValid($token)
  363. {
  364. if (empty($token)) {
  365. return false;
  366. }
  367. $expire = Yii::$app->params['user.passwordResetTokenExpire'];
  368. $parts = explode('_', $token);
  369. $timestamp = (int)end($parts);
  370. return $timestamp + $expire >= time();
  371. }
  372. /**
  373. * @inheritdoc
  374. */
  375. public function getId()
  376. {
  377. return $this->getPrimaryKey();
  378. }
  379. /**
  380. * @inheritdoc
  381. */
  382. public function getAuthKey()
  383. {
  384. return $this->auth_key;
  385. }
  386. /**
  387. * @inheritdoc
  388. */
  389. public function validateAuthKey($authKey)
  390. {
  391. return $this->getAuthKey() === $authKey;
  392. }
  393. /**
  394. * Validates password
  395. *
  396. * @param string $password password to validate
  397. * @return boolean if password provided is valid for current user
  398. */
  399. public function validatePassword($password)
  400. {
  401. return Yii::$app->security->validatePassword($password, $this->password_hash);
  402. }
  403. /**
  404. * Generates password hash from password and sets it to the model
  405. *
  406. * @param string $password
  407. */
  408. public function setPassword($password)
  409. {
  410. $this->password_hash = Yii::$app->security->generatePasswordHash($password);
  411. }
  412. /**
  413. * Generates "remember me" authentication key
  414. */
  415. public function generateAuthKey()
  416. {
  417. $this->auth_key = Yii::$app->security->generateRandomString();
  418. }
  419. /**
  420. * Generates new password reset token
  421. */
  422. public function generatePasswordResetToken()
  423. {
  424. $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
  425. }
  426. /**
  427. * Removes password reset token
  428. */
  429. public function removePasswordResetToken()
  430. {
  431. $this->password_reset_token = null;
  432. }
  433. /**
  434. * Retourne l'utilisateur courant.
  435. *
  436. * @return User
  437. */
  438. public static function getCurrent()
  439. {
  440. if (!Yii::$app->user->isGuest) {
  441. return Yii::$app->user->identity;
  442. }
  443. return false;
  444. }
  445. /**
  446. * Retourne si l'utilisateur courant est connecté ou non.
  447. *
  448. * @return boolean
  449. */
  450. public static function isCurrentConnected()
  451. {
  452. return !Yii::$app->user->isGuest;
  453. }
  454. /**
  455. * Retourne si l'utilisateur est un producteur ou non.
  456. *
  457. * @return boolean
  458. */
  459. public function isProducer()
  460. {
  461. return ($this->status == User::STATUS_ADMIN || $this->status == User::STATUS_PRODUCER) && $this->id_producer;
  462. }
  463. /**
  464. * Retourne si l'utilisateur courant est un producteur ou non.
  465. *
  466. * @return boolean
  467. */
  468. public static function isCurrentProducer()
  469. {
  470. $user = User::getCurrent();
  471. if ($user) {
  472. return $user->isProducer();
  473. }
  474. return false;
  475. }
  476. /**
  477. * Retourne si l'utilisateur est un admin ou non.
  478. *
  479. * @return boolean
  480. */
  481. public function isAdmin()
  482. {
  483. return $this->status == User::STATUS_ADMIN;
  484. }
  485. /**
  486. * Retourne si l'utilisateur courant est un admin ou non.
  487. *
  488. * @return boolean
  489. */
  490. public static function isCurrentAdmin()
  491. {
  492. $user = User::getCurrent();
  493. if ($user) {
  494. return $user->isAdmin();
  495. }
  496. return false;
  497. }
  498. /**
  499. * Retourne le nom du producteur.
  500. *
  501. * @return string
  502. */
  503. public function getNameProducer()
  504. {
  505. $producer = Producer::findOne($this->id_producer);
  506. return $producer->name;
  507. }
  508. /**
  509. * Retourne les établissements liés à l'utilisateur.
  510. *
  511. * @return array
  512. */
  513. public function getBookmarkedProducers()
  514. {
  515. $producers = (new \yii\db\Query())
  516. ->select('*')
  517. ->from(['user_producer', 'producer'])
  518. ->where('user_producer.id_producer = producer.id')
  519. ->andWhere(['user_producer.id_user' => $this->id])
  520. ->andWhere(['user_producer.active' => 1])
  521. ->all();
  522. return $producers;
  523. }
  524. /**
  525. * Retourne le crédit de l'utilisateur pour un producteur donné.
  526. *
  527. * @param integer $id_etablissement
  528. * @return float
  529. */
  530. public function getCredit($idProducer)
  531. {
  532. $userProducer = UserProducer::searchOne([
  533. 'id_user' => $this->id
  534. ]);
  535. if ($userProducer) {
  536. return $userProducer->credit;
  537. }
  538. return 0;
  539. }
  540. /**
  541. * Retourne le point de vente favoris d'un utilisateur : le point de vente auquel le client est lié,
  542. * le point de vente de la dernière commande sinon.
  543. *
  544. * @return PointSale
  545. */
  546. public function getFavoritePointSale()
  547. {
  548. $arrayUserPointSale = UserPointSale::find()
  549. ->innerJoinWith('pointSale', true)
  550. ->where([
  551. 'user_point_sale.id_user' => $this->id,
  552. 'point_sale.id_producer' => GlobalParam::getCurrentProducerId()
  553. ])
  554. ->all();
  555. if (count($arrayUserPointSale) == 1) {
  556. $pointSale = PointSale::findOne(['id' => $arrayUserPointSale[0]->id_point_sale]);
  557. } else {
  558. $lastOrder = Order::find()->innerJoinWith('pointSale', true)->where([
  559. 'order.id_user' => $this->id,
  560. 'point_sale.id_producer' => GlobalParam::getCurrentProducerId()
  561. ])
  562. ->orderBy('order.id DESC')
  563. ->one();
  564. if ($lastOrder) {
  565. $pointSale = PointSale::findOne(['id' => $lastOrder->id_point_sale]);
  566. }
  567. }
  568. if (isset($pointSale)) {
  569. return $pointSale;
  570. }
  571. return false;
  572. }
  573. /**
  574. * Met à jour la date de dernière connexion de l'utilisateur.
  575. */
  576. public function updateLastConnection()
  577. {
  578. $this->date_last_connection = date('Y-m-d H:i:s');
  579. $this->save();
  580. }
  581. /**
  582. * Envoie un email de bienvenue à l'utilisateur lors de son inscription
  583. * via le backend du site.
  584. *
  585. * @param string $password
  586. */
  587. public function sendMailWelcome($password)
  588. {
  589. if (strlen($this->email)) {
  590. $producer = Producer::findOne(GlobalParam::getCurrentProducerId());
  591. Yii::$app->mailer->compose();
  592. $mail = Yii::$app->mailer->compose(
  593. ['html' => 'createUserAdmin-html', 'text' => 'createUserAdmin-text'], ['user' => $this, 'producer' => $producer, 'password' => $password]
  594. )
  595. ->setTo($this->email)
  596. ->setFrom(['contact@opendistrib.net' => 'distrib'])
  597. ->setSubject('[distrib] Inscription')
  598. ->send();
  599. }
  600. }
  601. public function getFullAddress($nl2br = false)
  602. {
  603. $address = '';
  604. if(isset($this->lastname) && isset($this->name) && strlen($this->lastname) && strlen($this->name)) {
  605. $address .= $this->lastname . ' ' . $this->name . "\n";
  606. }
  607. if(isset($this->name_legal_person) && strlen($this->name_legal_person)) {
  608. $address .= $this->name_legal_person. "\n";
  609. }
  610. $address .= $this->address;
  611. if($nl2br) {
  612. $address = nl2br($address) ;
  613. }
  614. return $address;
  615. }
  616. public function getUsername()
  617. {
  618. $username = '' ;
  619. if(isset($this->name_legal_person) && strlen($this->name_legal_person)) {
  620. $username = $this->name_legal_person ;
  621. }
  622. else {
  623. $username = $this->lastname.' '.$this->name ;
  624. }
  625. return $username ;
  626. }
  627. /**
  628. * Retourne l'ID de l'utilisateur courant connecté.
  629. *
  630. * @return mixed
  631. */
  632. public static function getCurrentId()
  633. {
  634. if (!Yii::$app->user->isGuest) {
  635. return Yii::$app->user->identity->id;
  636. }
  637. return false;
  638. }
  639. /**
  640. * Retourne le status de l'utilisateur courant connecté.
  641. *
  642. * @return integer|boolean
  643. */
  644. public static function getCurrentStatus()
  645. {
  646. if (!Yii::$app->user->isGuest) {
  647. return Yii::$app->user->identity->status;
  648. }
  649. return false;
  650. }
  651. public static function hasAccessBackend()
  652. {
  653. return User::getCurrentStatus() == USER::STATUS_ADMIN || User::getCurrentStatus() == USER::STATUS_PRODUCER;
  654. }
  655. }