Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

683 lines
23KB

  1. <?php
  2. /**
  3. * Copyright Souke (2018)
  4. *
  5. * contact@souke.fr
  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 frontend\controllers;
  38. use common\helpers\GlobalParam;
  39. use frontend\forms\OpinionForm;
  40. use frontend\forms\ProducerCodeForm;
  41. use GuzzleHttp\Client;
  42. use Yii;
  43. use frontend\forms\PasswordResetRequestForm;
  44. use frontend\forms\ResetPasswordForm;
  45. use frontend\forms\SignupForm;
  46. use common\forms\ContactForm;
  47. use yii\base\InvalidParamException;
  48. use yii\base\UserException;
  49. use yii\data\ActiveDataProvider;
  50. use yii\helpers\Html;
  51. use yii\web\BadRequestHttpException;
  52. use yii\filters\VerbFilter;
  53. use yii\filters\AccessControl;
  54. use common\forms\LoginForm;
  55. use yii\web\NotFoundHttpException;
  56. /**
  57. * Site controller
  58. */
  59. class SiteController extends FrontendController
  60. {
  61. /**
  62. * @inheritdoc
  63. */
  64. public function behaviors()
  65. {
  66. return [
  67. 'access' => [
  68. 'class' => AccessControl::class,
  69. 'only' => ['logout', 'signup', 'signup-producer'],
  70. 'rules' => [
  71. [
  72. 'actions' => ['signup'],
  73. 'allow' => true,
  74. 'roles' => ['?'],
  75. ],
  76. [
  77. 'actions' => ['signup-producer'],
  78. 'allow' => true,
  79. 'roles' => ['@'],
  80. ],
  81. [
  82. 'actions' => ['logout'],
  83. 'allow' => true,
  84. 'roles' => ['@'],
  85. ],
  86. ],
  87. 'denyCallback' => function($rule, $action) {
  88. return $this->redirect('index');
  89. }
  90. ],
  91. 'verbs' => [
  92. 'class' => VerbFilter::class,
  93. 'actions' => [
  94. 'logout' => ['get'],
  95. ],
  96. ],
  97. ];
  98. }
  99. /**
  100. * @inheritdoc
  101. */
  102. public function actions()
  103. {
  104. return [
  105. 'captcha' => [
  106. 'class' => 'yii\captcha\CaptchaAction',
  107. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  108. ],
  109. ];
  110. }
  111. /**
  112. * Affiche la page d'erreur.
  113. *
  114. * @return mixed
  115. */
  116. public function actionError()
  117. {
  118. $exception = \Yii::$app->errorHandler->exception;
  119. if ($exception->getMessage() == 'Producteur introuvable'
  120. || \Yii::$app->getRequest()->getQueryParam('producer_not_found')) {
  121. return $this->render('error-404-producer', ['exception' => $exception]);
  122. }
  123. if ($exception !== null) {
  124. return $this->render('error', ['exception' => $exception]);
  125. }
  126. }
  127. public function actionIndex()
  128. {
  129. $dataProviderProducers = new ActiveDataProvider([
  130. 'query' => $this->getProducerModule()->queryProducersActive('producer.date_creation', 'DESC')->query(),
  131. 'pagination' => [
  132. 'pageSize' => 100,
  133. ],
  134. ]);
  135. return $this->render('index', [
  136. 'dataProviderProducers' => $dataProviderProducers,
  137. 'producersArray' => $this->getProducerModule()->findProducersActive('producer.date_creation', 'DESC')
  138. ]);
  139. }
  140. public function actionIamproducer()
  141. {
  142. return $this->render('iamproducer', []);
  143. }
  144. public function actionService()
  145. {
  146. $paidFeaturesArray = $this->getFeatureModule()->getRepository()->findPaidFeatures();
  147. return $this->render('service', [
  148. 'producerDemoAccount' => $this->getProducerModule()->findOneProducerDemoAccount(),
  149. 'dataProviderPrices' => $this->getDataProviderPrices(),
  150. 'paidFeaturesArray' => $paidFeaturesArray
  151. ]);
  152. }
  153. public function getDataProviderPrices()
  154. {
  155. return new ActiveDataProvider([
  156. 'query' => $this->getProducerPriceRangeModule()->queryProducerPriceRanges()->query(),
  157. 'pagination' => [
  158. 'pageSize' => 100,
  159. ],
  160. ]);
  161. }
  162. public function actionProducers()
  163. {
  164. return $this->render('producer', [
  165. 'maximumNumberProducers' => $this->getSettingModule()->getAdminSettingBag()->get('maximumNumberProducers'),
  166. 'countProducersActive' => $this->getProducerModule()->getRepository()->countCacheProducersActiveWithTurnover()
  167. ]);
  168. }
  169. public function actionAbout()
  170. {
  171. $aboutFewNumbers = Yii::$app->cache->getOrSet('about_few_numbers4', function () {
  172. $producerModule = $this->getProducerModule();
  173. $pointSaleModule = $this->getPointSaleModule();
  174. $userModule = $this->getUserModule();
  175. $orderModule = $this->getOrderModule();
  176. $countProducersActive = $producerModule->getRepository()->countProducersActiveWithTurnover();
  177. $timeSavedByProducersAverage = $producerModule->getTimeSavedByProducersAverage();
  178. $countProducersWithOptionTimeSaved = $producerModule->countProducersWithTimeSaved();
  179. $countPointSalesActive = $pointSaleModule->countPointSalesActiveLastThreeMonths();
  180. $countUsersActive = $userModule->countUsersActiveLastThreeMonths();
  181. $averageOrdersPerDay = $orderModule->countGlobalUserOrdersAverageLastSevenDays();
  182. $turnoverLastThirtyDays = $orderModule->getRepository()->getTurnoverLastThirtyDays();
  183. $resultMatomoApiVisitSummary = json_decode(file_get_contents(Yii::$app->parameterBag->get('matomoApiVisitSummaryUrl')));
  184. $numberVisitsByDay = $resultMatomoApiVisitSummary->nb_uniq_visitors / 30;
  185. return $this->renderPartial('_about_few_numbers', [
  186. 'countProducersActive' => $countProducersActive,
  187. 'countPointSalesActive' => $countPointSalesActive,
  188. 'countUsersActive' => $countUsersActive,
  189. 'averageOrdersPerDay' => $averageOrdersPerDay,
  190. 'turnoverLastThirtyDays' => $turnoverLastThirtyDays,
  191. 'numberVisitsByDay' => $numberVisitsByDay,
  192. 'timeSavedByProducersAverage' => $timeSavedByProducersAverage,
  193. 'countProducersWithOptionTimeSaved' => $countProducersWithOptionTimeSaved
  194. ]);
  195. }, 60 * 60 * 24);
  196. $producerModule = $this->getProducerModule();
  197. return $this->render('about', [
  198. 'countProducers' => $producerModule->countProducersActiveWithTurnover(),
  199. 'producersWithTestimonials' => $producerModule->findProducersWithTestimonials(),
  200. 'aboutFewNumbers' => $aboutFewNumbers
  201. ]);
  202. }
  203. /*public function actionSourceCode()
  204. {
  205. return $this->render('source_code');
  206. }*/
  207. /**
  208. * Liste les producteurs utilisant la plateforme.
  209. */
  210. public function actionAjaxProducers()
  211. {
  212. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  213. $producersArray = $this->getProducerModule()->findProducersActive();
  214. $producersArrayReturn = [];
  215. foreach($producersArray as $producer) {
  216. $producersArrayReturn[] = [
  217. 'id' => $producer->id,
  218. 'name' => Html::encode($producer->name),
  219. 'type' => Html::encode($producer->type),
  220. 'address' => Html::encode($producer->postcode.' '.$producer->city),
  221. 'latitude' => $producer->latitude,
  222. 'longitude' => $producer->longitude,
  223. 'link' => $this->getUrlManagerProducer()->createAbsoluteUrl(['site/index', 'slug_producer' => $producer->slug])
  224. ];
  225. }
  226. return $producersArrayReturn;
  227. }
  228. /**
  229. * Affiche la page de connexion et traite le formulaire de connexion.
  230. */
  231. public function actionLogin()
  232. {
  233. if (!\Yii::$app->user->isGuest) {
  234. return \Yii::$app->getResponse()->redirect(['site/index']);
  235. }
  236. $model = new LoginForm();
  237. if ($model->load(Yii::$app->request->post()) && $model->login()) {
  238. $returnUrl = \Yii::$app->request->get('return_url');
  239. if ($returnUrl) {
  240. return $this->redirect($returnUrl);
  241. }
  242. else {
  243. $userProducerArray = $this->getUserProducerModule()->findUserProducersByUser(GlobalParam::getCurrentUser());
  244. if ($userProducerArray
  245. && is_array($userProducerArray)
  246. && count($userProducerArray) == 1) {
  247. $urlRedirect = $this->getUrlManagerProducer()
  248. ->createAbsoluteUrl([
  249. 'site/index',
  250. 'slug_producer' => $userProducerArray[0]->producer->slug
  251. ]);
  252. return $this->redirect($urlRedirect);
  253. }
  254. else {
  255. return $this->goBack();
  256. }
  257. }
  258. } else {
  259. return $this->render('@frontend/views/site/login', [
  260. 'model' => $model,
  261. ]);
  262. }
  263. }
  264. /**
  265. * Déconnecte l'utilisateur.
  266. */
  267. public function actionLogout()
  268. {
  269. \Yii::$app->user->logout();
  270. $referer = Yii::$app->request->referrer ?: Yii::$app->homeUrl;
  271. // @TODO : comprendre pourquoi le referer n'est pas complet en ligne (slug producteur + controller/action absents)
  272. if($referer == 'https://'.Yii::getAlias('@producerSubdomain').'.'.Yii::getAlias('@domainName').'/') {
  273. return $this->redirect(Yii::$app->homeUrl);
  274. }
  275. $authenticatedActions = [
  276. // frontend
  277. 'user/update',
  278. // producer
  279. 'order/order',
  280. 'order/history',
  281. 'subscription/index',
  282. 'subscription/form',
  283. 'credit/history',
  284. 'credit/add',
  285. 'newsletter/index'
  286. ];
  287. foreach($authenticatedActions as $authenticatedAction) {
  288. $pos = strpos($referer, $authenticatedAction);
  289. if($pos !== false) {
  290. $referer = substr($referer, 0, $pos);
  291. }
  292. }
  293. return $this->redirect($referer);
  294. }
  295. /**
  296. * Affiche la page de contact et traite le formulaire s'il est soumis.
  297. */
  298. public function actionContact()
  299. {
  300. $model = new ContactForm();
  301. $messageSent = false;
  302. if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  303. $model->sendEmailAdmin();
  304. $messageSent = true;
  305. $model = new ContactForm();
  306. }
  307. return $this->render('contact', [
  308. 'model' => $model,
  309. 'messageSent' => $messageSent,
  310. ]);
  311. }
  312. /**
  313. * Affiche la page d'inscription et traite son formulaire.
  314. */
  315. public function actionSignup(string $type = 'user')
  316. {
  317. $model = new SignupForm();
  318. $model->option_user_producer = $type;
  319. $producerModule = $this->getProducerModule();
  320. if ($model->load(Yii::$app->request->post())) {
  321. $user = $model->signup();
  322. if ($user && Yii::$app->getUser()->login($user)) {
  323. if ($model->isProducer()) {
  324. $this->redirect(['site/signup-confirm']);
  325. }
  326. else {
  327. $producer = $producerModule->findOneProducerById($model->id_producer);
  328. if ($producer) {
  329. $this->redirect(['site/signup-confirm', 'idProducerRedirect' => $producer->id]);
  330. }
  331. else {
  332. $this->redirect(['site/index']);
  333. }
  334. }
  335. }
  336. }
  337. // Liste des producteurs disponibles
  338. $producersArray = $producerModule->populateProducerDropdown();
  339. $dataProducers = $producersArray['data'];
  340. $optionsProducers = $producersArray['options'];
  341. $paidFeaturesArray = $this->getFeatureModule()->getRepository()->findPaidFeatures();
  342. return $this->render('signup', [
  343. 'model' => $model,
  344. 'dataProducers' => $dataProducers,
  345. 'dataProviderPrices' => $this->getDataProviderPrices(),
  346. 'paidFeaturesArray' => $paidFeaturesArray,
  347. 'optionsProducers' => $optionsProducers,
  348. ]);
  349. }
  350. public function actionSignupProducer()
  351. {
  352. $model = new SignupForm();
  353. $model->signup_producer_only = 'producer';
  354. $model->option_user_producer = 'producer';
  355. if ($model->load(Yii::$app->request->post())) {
  356. $user = $model->signup($this->getUserCurrent());
  357. if($user) {
  358. $this->redirect(['site/signup-confirm']);
  359. }
  360. }
  361. return $this->render('signup_producer', [
  362. 'model' => $model,
  363. 'dataProviderPrices' => $this->getDataProviderPrices(),
  364. 'paidFeaturesArray' => $this->getFeatureModule()->getRepository()->findPaidFeatures()
  365. ]);
  366. }
  367. public function actionSignupConfirm($idProducerRedirect = null)
  368. {
  369. $producerModule = $this->getProducerModule();
  370. $user = $this->getUserCurrent();
  371. $producerRedirect = $idProducerRedirect ? $producerModule->findOneProducerById($idProducerRedirect) : null ;
  372. if(!$user) {
  373. throw new NotFoundHttpException('Page introuvable');
  374. }
  375. return $this->render('signup_confirm', [
  376. 'user' => $user,
  377. 'producerRedirect' => $producerRedirect
  378. ]);
  379. }
  380. /**
  381. * Affiche la page de demande de nouveau mot de passe.
  382. * Traitement du formulaire.
  383. */
  384. public function actionRequestPasswordReset()
  385. {
  386. $model = new PasswordResetRequestForm();
  387. if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  388. if ($model->sendEmail()) {
  389. $this->setFlash('success', 'Un lien vous permettant de réinitialiser votre mot de passe
  390. vient d\'être envoyé sur votre boîte mail.');
  391. return $this->goHome();
  392. }
  393. else {
  394. $this->setFlash('error', 'Sorry, we are unable to reset password for email provided.');
  395. }
  396. }
  397. return $this->render('requestPasswordResetToken', [
  398. 'model' => $model,
  399. ]);
  400. }
  401. /**
  402. * Met à jour le mot de passe de l'utilisateur.
  403. */
  404. public function actionResetPassword($token)
  405. {
  406. try {
  407. $model = new ResetPasswordForm($token);
  408. } catch (InvalidParamException $e) {
  409. throw new BadRequestHttpException($e->getMessage());
  410. }
  411. if ($model->load($this->getRequest()->post())
  412. && $model->validate()
  413. && $model->resetPassword()) {
  414. $this->setFlash('success', 'Votre nouveau mot de passe vient d\'être sauvegardé.');
  415. return $this->goHome();
  416. }
  417. return $this->render('resetPassword', [
  418. 'model' => $model,
  419. ]);
  420. }
  421. /**
  422. * Affiche le formulaire de demande de code pour accéder à certains producteurs.
  423. */
  424. public function actionProducerCode(int $id)
  425. {
  426. $producerModule = $this->getProducerModule();
  427. $producer = $producerModule->findOneProducerById($id);
  428. if (!$producer) {
  429. throw new \yii\web\HttpException(404, 'Producteur introuvable');
  430. }
  431. $producerCodeForm = new ProducerCodeForm();
  432. $producerCodeForm->id_producer = $id;
  433. if ($producerCodeForm->load($this->getRequest()->post())
  434. && $producerCodeForm->validate()) {
  435. $this->getLogic()->setProducerContext($producer);
  436. $producerModule->addUser(GlobalParam::getCurrentUser(), $producer);
  437. $this->redirect($this->getUrlManagerProducer()->createAbsoluteUrl(['site/index', 'slug_producer' => $producer->slug]));
  438. }
  439. return $this->render('producer_code', [
  440. 'producer' => $producer,
  441. 'producerCodeForm' => $producerCodeForm,
  442. ]);
  443. }
  444. /**
  445. * Affiche la page de connexion / inscription pour accéder notamment au
  446. * formulaire de commande des producteurs.
  447. */
  448. public function actionProducer(int $id)
  449. {
  450. $loginForm = new LoginForm();
  451. $signupForm = new SignupForm();
  452. $producerModule = $this->getProducerModule();
  453. $producer = $producerModule->findOneProducerById($id);
  454. $this->getLogic()->setProducerContext($producer);
  455. $loginForm->id_producer = $id;
  456. $signupForm->id_producer = $id;
  457. $signupForm->option_user_producer = 'user';
  458. $returnUrl = $this->getRequest()->get('return_url', $this->getUrlManagerProducer()->createAbsoluteUrl(['site/index', 'slug_producer' => $producer->slug]));
  459. if (Yii::$app->user->isGuest) {
  460. if ($loginForm->load($this->getRequest()->post()) && $loginForm->login()) {
  461. if (!strlen($producer->code)) {
  462. $producerModule->addUser(GlobalParam::getCurrentUser(), $producer);
  463. }
  464. $this->redirect($returnUrl);
  465. }
  466. if ($signupForm->load($this->getRequest()->post())
  467. && ($user = $signupForm->signup())
  468. && Yii::$app->user->login($user)) {
  469. $this->redirect($returnUrl);
  470. }
  471. }
  472. else {
  473. $this->redirect($returnUrl);
  474. }
  475. return $this->render('producer', [
  476. 'loginForm' => $loginForm,
  477. 'signupForm' => $signupForm,
  478. 'producer' => $producer,
  479. ]);
  480. }
  481. /**
  482. * Indique à l'utilisateur que l'espace d'un producteur est hors ligne.
  483. */
  484. public function actionProducerOffline(int $id)
  485. {
  486. return $this->render('producer_offline', [
  487. 'producer' => $this->getProducerModule()->findOneProducerById($id),
  488. ]);
  489. }
  490. public function actionOpinion()
  491. {
  492. $opinionFormModel = new OpinionForm();
  493. $opinionSent = false;
  494. if ($opinionFormModel->load(Yii::$app->request->post()) && $opinionFormModel->validate()) {
  495. $this->getOpinionModule()->getManager()
  496. ->sendOpinionEmailAdmin($opinionFormModel, $this->getUserCurrent());
  497. $opinionSent = true;
  498. $opinionFormModel = new OpinionForm();
  499. }
  500. return $this->render('opinion', [
  501. 'model' => $opinionFormModel,
  502. 'opinionSent' => $opinionSent
  503. ]);
  504. }
  505. /**
  506. * Affiche les mentions légales.
  507. */
  508. public function actionMentions()
  509. {
  510. return $this->render('mentions');
  511. }
  512. /**
  513. * Affiche les conditions générale de service.
  514. */
  515. public function actionCgv()
  516. {
  517. return $this->render('cgv');
  518. }
  519. /**
  520. * Affiche les précisions concernant l'utilisation de la cagnotte
  521. */
  522. public function actionCredit()
  523. {
  524. return $this->render('credit');
  525. }
  526. public function actionImageProducersLogos()
  527. {
  528. $image = @imagecreatetruecolor(1600, 1200);
  529. // fond en blanc
  530. $whiteBackground = imagecolorallocate($image, 255, 255, 255);
  531. imagefill($image,0,0,$whiteBackground);
  532. // logos des producteurs
  533. $producerModule = $this->getProducerModule();
  534. $producersArray = $producerModule->getRepository()->findProducersActive();
  535. shuffle($producersArray);
  536. $x = 50;
  537. $y = 0;
  538. foreach($producersArray as $producer) {
  539. if($producer->logo) {
  540. $logo = null;
  541. $srcLogo = dirname(__FILE__).'/../../producer/web/uploads/'.$producer->logo;
  542. $imageType = exif_imagetype($srcLogo);
  543. if($imageType == IMAGETYPE_PNG) {
  544. $logo = imagecreatefrompng($srcLogo);
  545. $backgroundBlack = imagecolorallocate($logo , 0, 0, 0);
  546. imagecolortransparent($logo, $backgroundBlack);
  547. }
  548. elseif($imageType == IMAGETYPE_JPEG) {
  549. $logo = imagecreatefromjpeg($srcLogo);
  550. }
  551. if($logo) {
  552. imagealphablending($logo, false);
  553. imagesavealpha($logo, true);
  554. list(
  555. $sourceImageWidth,
  556. $sourceImageHeight
  557. ) = getimagesize( $srcLogo);
  558. if($sourceImageWidth && $sourceImageHeight) {
  559. $targetImageWidth = 120;
  560. $targetImageHeight = 120;
  561. $sourceAspectRatio = $sourceImageWidth / $sourceImageHeight;
  562. $targetAspectRatio = $targetImageWidth / $targetImageHeight;
  563. if ($targetAspectRatio > $sourceAspectRatio) {
  564. $targetImageHeight = (int) ($targetImageWidth / $sourceAspectRatio);
  565. }
  566. else {
  567. $targetImageWidth = (int) ($targetImageHeight * $sourceAspectRatio);
  568. }
  569. $transparency = 0.7;
  570. imagefilter($logo, IMG_FILTER_COLORIZE, 0,0,0,127 * $transparency);
  571. imagecopyresampled($image, $logo, $x, $y + 60, 0, 0, $targetImageWidth, $targetImageHeight, $sourceImageWidth, $sourceImageHeight);
  572. $x += $targetImageWidth + 75;
  573. if($x > 1600) {
  574. $x = rand(-50, 50);
  575. $y += 200;
  576. }
  577. }
  578. }
  579. }
  580. }
  581. // noir et blanc
  582. imagefilter($image, IMG_FILTER_GRAYSCALE);
  583. // rendu de l'image
  584. header ('Content-Type: image/png');
  585. imagepng($image);
  586. imagedestroy($image);
  587. die();
  588. }
  589. }