549 lines
18KB

  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 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'],
  70. 'rules' => [
  71. [
  72. 'actions' => ['signup'],
  73. 'allow' => true,
  74. 'roles' => ['?'],
  75. ],
  76. [
  77. 'actions' => ['logout'],
  78. 'allow' => true,
  79. 'roles' => ['@'],
  80. ],
  81. ],
  82. ],
  83. 'verbs' => [
  84. 'class' => VerbFilter::class,
  85. 'actions' => [
  86. 'logout' => ['get'],
  87. ],
  88. ],
  89. ];
  90. }
  91. /**
  92. * @inheritdoc
  93. */
  94. public function actions()
  95. {
  96. return [
  97. 'captcha' => [
  98. 'class' => 'yii\captcha\CaptchaAction',
  99. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  100. ],
  101. ];
  102. }
  103. /**
  104. * Affiche la page d'erreur.
  105. *
  106. * @return mixed
  107. */
  108. public function actionError()
  109. {
  110. $exception = \Yii::$app->errorHandler->exception;
  111. if ($exception->getMessage() == 'Producteur introuvable'
  112. || \Yii::$app->getRequest()->getQueryParam('producer_not_found')) {
  113. return $this->render('error-404-producer', ['exception' => $exception]);
  114. }
  115. if ($exception !== null) {
  116. return $this->render('error', ['exception' => $exception]);
  117. }
  118. }
  119. /**
  120. * Affiche la page d'accueil.
  121. */
  122. public function actionIndex()
  123. {
  124. return $this->render('index');
  125. }
  126. public function actionService()
  127. {
  128. return $this->render('service', [
  129. 'producerDemoAccount' => $this->getProducerManager()->findOneProducerDemoAccount(),
  130. 'dataProviderPrices' => $this->getDataProviderPrices()
  131. ]);
  132. }
  133. public function getDataProviderPrices()
  134. {
  135. return new ActiveDataProvider([
  136. 'query' => $this->getProducerPriceRangeManager()->queryProducerPriceRanges()->query(),
  137. 'pagination' => [
  138. 'pageSize' => 100,
  139. ],
  140. ]);
  141. }
  142. /**
  143. * Liste les producteurs utilisant la plateforme.
  144. */
  145. public function actionProducers()
  146. {
  147. $dataProviderProducers = new ActiveDataProvider([
  148. 'query' => $this->getProducerManager()->queryProducersActive()->query(),
  149. 'pagination' => [
  150. 'pageSize' => 100,
  151. ],
  152. ]);
  153. return $this->render('producers', [
  154. 'dataProviderProducers' => $dataProviderProducers,
  155. 'producersArray' => $this->getProducerManager()->findProducersActive()
  156. ]);
  157. }
  158. public function actionAbout()
  159. {
  160. $aboutFewNumbers = Yii::$app->cache->getOrSet('about_few_numbers7', function () {
  161. $producerManager = $this->getProducerManager();
  162. $pointSaleManager = $this->getPointSaleManager();
  163. $userManager = $this->getUserManager();
  164. $orderManager = $this->getOrderManager();
  165. $countProducersActive = $producerManager->countProducersActiveWithTurnover();
  166. $timeSavedByProducersAverage = $producerManager->getTimeSavedByProducersAverage();
  167. $countProducersWithOptionTimeSaved = $producerManager->countProducersWithTimeSaved();
  168. $countPointSalesActive = $pointSaleManager->countPointSalesActiveLastThreeMonths();
  169. $countUsersActive = $userManager->countUsersActiveLastThreeMonths();
  170. $averageOrdersPerDay = $orderManager->countGlobalUserOrdersAverageLastSevenDays();
  171. $averageTurnover = $orderManager->getAverageTurnoverLastThreeMonths();
  172. $resultMatomoApiVisitSummary = json_decode(file_get_contents(Yii::$app->parameterBag->get('matomoApiVisitSummaryUrl')));
  173. $numberVisitsMonth = $resultMatomoApiVisitSummary->nb_uniq_visitors;
  174. return $this->renderPartial('_about_few_numbers', [
  175. 'countProducersActive' => $countProducersActive,
  176. 'countPointSalesActive' => $countPointSalesActive,
  177. 'countUsersActive' => $countUsersActive,
  178. 'averageOrdersPerDay' => $averageOrdersPerDay,
  179. 'averageTurnover' => $averageTurnover,
  180. 'numberVisitsMonth' => $numberVisitsMonth,
  181. 'timeSavedByProducersAverage' => $timeSavedByProducersAverage,
  182. 'countProducersWithOptionTimeSaved' => $countProducersWithOptionTimeSaved
  183. ]);
  184. }, 60 * 60 * 24);
  185. $producerManager = $this->getProducerManager();
  186. return $this->render('about', [
  187. 'countProducers' => $producerManager->countProducersActiveWithTurnover(),
  188. 'producersWithTestimonials' => $producerManager->findProducersWithTestimonials(),
  189. 'aboutFewNumbers' => $aboutFewNumbers
  190. ]);
  191. }
  192. public function actionSourceCode()
  193. {
  194. return $this->render('source_code');
  195. }
  196. /**
  197. * Liste les producteurs utilisant la plateforme.
  198. */
  199. public function actionAjaxProducers()
  200. {
  201. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  202. $producersArray = $this->getProducerManager()->findProducersActive();
  203. $producersArrayReturn = [];
  204. foreach($producersArray as $producer) {
  205. $producersArrayReturn[] = [
  206. 'id' => $producer->id,
  207. 'name' => Html::encode($producer->name),
  208. 'type' => Html::encode($producer->type),
  209. 'address' => Html::encode($producer->postcode.' '.$producer->city),
  210. 'latitude' => $producer->latitude,
  211. 'longitude' => $producer->longitude,
  212. 'link' => $this->getUrlManagerProducer()->createAbsoluteUrl(['site/index', 'slug_producer' => $producer->slug])
  213. ];
  214. }
  215. return $producersArrayReturn;
  216. }
  217. /**
  218. * Affiche la page de connexion et traite le formulaire de connexion.
  219. */
  220. public function actionLogin()
  221. {
  222. if (!\Yii::$app->user->isGuest) {
  223. return \Yii::$app->getResponse()->redirect(['site/index']);
  224. }
  225. $model = new LoginForm();
  226. if ($model->load(Yii::$app->request->post()) && $model->login()) {
  227. $returnUrl = \Yii::$app->request->get('return_url');
  228. if ($returnUrl) {
  229. return $this->redirect($returnUrl);
  230. }
  231. else {
  232. $userProducerArray = $this->getUserProducerManager()->findUserProducersByUser(GlobalParam::getCurrentUser());
  233. if ($userProducerArray
  234. && is_array($userProducerArray)
  235. && count($userProducerArray) == 1) {
  236. $urlRedirect = $this->getUrlManagerProducer()
  237. ->createAbsoluteUrl([
  238. 'site/index',
  239. 'slug_producer' => $userProducerArray[0]->producer->slug
  240. ]);
  241. return $this->redirect($urlRedirect);
  242. }
  243. else {
  244. return $this->goBack();
  245. }
  246. }
  247. } else {
  248. return $this->render('@frontend/views/site/login', [
  249. 'model' => $model,
  250. ]);
  251. }
  252. }
  253. /**
  254. * Déconnecte l'utilisateur.
  255. */
  256. public function actionLogout()
  257. {
  258. \Yii::$app->user->logout();
  259. return $this->goHome();
  260. }
  261. /**
  262. * Affiche la page de contact et traite le formulaire s'il est soumis.
  263. */
  264. public function actionContact()
  265. {
  266. $model = new ContactForm();
  267. $messageSent = false;
  268. if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  269. $model->sendEmail(Yii::$app->parameterBag->get('adminEmail'));
  270. $messageSent = true;
  271. }
  272. return $this->render('contact', [
  273. 'model' => $model,
  274. 'messageSent' => $messageSent,
  275. ]);
  276. }
  277. /**
  278. * Affiche la page d'inscription et traite son formulaire.
  279. */
  280. public function actionSignup()
  281. {
  282. $model = new SignupForm();
  283. $producerManager = $this->getProducerManager();
  284. if ($model->load(Yii::$app->request->post())) {
  285. $user = $model->signup();
  286. if ($user && Yii::$app->getUser()->login($user)) {
  287. if ($model->isProducer()) {
  288. $this->redirect(['site/signup-confirm']);
  289. }
  290. else {
  291. $producer = $producerManager->findOneProducerById($model->id_producer);
  292. if ($producer) {
  293. $this->redirect(['site/signup-confirm', 'idProducerRedirect' => $producer->id]);
  294. }
  295. else {
  296. $this->redirect(['site/index']);
  297. }
  298. }
  299. }
  300. }
  301. // Liste des producteurs disponibles
  302. $producersArray = $producerManager->populateProducerDropdown();
  303. $dataProducers = $producersArray['data'];
  304. $optionsProducers = $producersArray['options'];
  305. return $this->render('signup', [
  306. 'model' => $model,
  307. 'dataProducers' => $dataProducers,
  308. 'dataProviderPrices' => $this->getDataProviderPrices(),
  309. 'optionsProducers' => $optionsProducers,
  310. ]);
  311. }
  312. public function actionSignupConfirm($idProducerRedirect = null)
  313. {
  314. $producerManager = $this->getProducerManager();
  315. $user = $this->getUserCurrent();
  316. $producerRedirect = $idProducerRedirect ? $producerManager->findOneProducerById($idProducerRedirect) : null ;
  317. if(!$user) {
  318. throw new NotFoundHttpException('Page introuvable');
  319. }
  320. return $this->render('signup_confirm', [
  321. 'user' => $user,
  322. 'producerRedirect' => $producerRedirect
  323. ]);
  324. }
  325. /**
  326. * Affiche la page de demande de nouveau mot de passe.
  327. * Traitement du formulaire.
  328. */
  329. public function actionRequestPasswordReset()
  330. {
  331. $model = new PasswordResetRequestForm();
  332. if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  333. if ($model->sendEmail()) {
  334. $this->setFlash('success', 'Un lien vous permettant de réinitialiser votre mot de passe
  335. vient d\'être envoyé sur votre boîte mail.');
  336. return $this->goHome();
  337. }
  338. else {
  339. $this->setFlash('error', 'Sorry, we are unable to reset password for email provided.');
  340. }
  341. }
  342. return $this->render('requestPasswordResetToken', [
  343. 'model' => $model,
  344. ]);
  345. }
  346. /**
  347. * Met à jour le mot de passe de l'utilisateur.
  348. */
  349. public function actionResetPassword($token)
  350. {
  351. try {
  352. $model = new ResetPasswordForm($token);
  353. } catch (InvalidParamException $e) {
  354. throw new BadRequestHttpException($e->getMessage());
  355. }
  356. if ($model->load($this->getRequest()->post())
  357. && $model->validate()
  358. && $model->resetPassword()) {
  359. $this->setFlash('success', 'Votre nouveau mot de passe vient d\'être sauvegardé.');
  360. return $this->goHome();
  361. }
  362. return $this->render('resetPassword', [
  363. 'model' => $model,
  364. ]);
  365. }
  366. /**
  367. * Affiche le formulaire de demande de code pour accéder à certains producteurs.
  368. */
  369. public function actionProducerCode(int $id)
  370. {
  371. $producerManager = $this->getProducerManager();
  372. $producer = $producerManager->findOneProducerById($id);
  373. if (!$producer) {
  374. throw new \yii\web\HttpException(404, 'Producteur introuvable');
  375. }
  376. $producerCodeForm = new ProducerCodeForm();
  377. $producerCodeForm->id_producer = $id;
  378. if ($producerCodeForm->load($this->getRequest()->post())
  379. && $producerCodeForm->validate()) {
  380. $this->getLogic()->setProducerContext($producer);
  381. $producerManager->addUser(GlobalParam::getCurrentUser(), $producer);
  382. $this->redirect($this->getUrlManagerProducer()->createAbsoluteUrl(['site/index', 'slug_producer' => $producer->slug]));
  383. }
  384. return $this->render('producer_code', [
  385. 'producer' => $producer,
  386. 'producerCodeForm' => $producerCodeForm,
  387. ]);
  388. }
  389. /**
  390. * Affiche la page de connexion / inscription pour accéder notamment au
  391. * formulaire de commande des producteurs.
  392. */
  393. public function actionProducer(int $id)
  394. {
  395. $loginForm = new LoginForm();
  396. $signupForm = new SignupForm();
  397. $producerManager = $this->getProducerManager();
  398. $producer = $producerManager->findOneProducerById($id);
  399. $this->getLogic()->setProducerContext($producer);
  400. $loginForm->id_producer = $id;
  401. $signupForm->id_producer = $id;
  402. $signupForm->option_user_producer = 'user';
  403. $returnUrl = $this->getRequest()->get('returnUrl', $this->getUrlManagerProducer()->createAbsoluteUrl(['site/index', 'slug_producer' => $producer->slug]));
  404. if (Yii::$app->user->isGuest) {
  405. if ($loginForm->load($this->getRequest()->post()) && $loginForm->login()) {
  406. if (!strlen($producer->code)) {
  407. $producerManager->addUser(GlobalParam::getCurrentUser(), $producer);
  408. }
  409. $this->redirect($returnUrl);
  410. }
  411. if ($signupForm->load($this->getRequest()->post())
  412. && ($user = $signupForm->signup())
  413. && Yii::$app->user->login($user)) {
  414. $this->redirect($returnUrl);
  415. }
  416. }
  417. else {
  418. $this->redirect($returnUrl);
  419. }
  420. return $this->render('producer', [
  421. 'loginForm' => $loginForm,
  422. 'signupForm' => $signupForm,
  423. 'producer' => $producer,
  424. ]);
  425. }
  426. /**
  427. * Indique à l'utilisateur que l'espace d'un producteur est hors ligne.
  428. */
  429. public function actionProducerOffline(int $id)
  430. {
  431. return $this->render('producer_offline', [
  432. 'producer' => $this->getProducerManager()->findOneProducerById($id),
  433. ]);
  434. }
  435. public function actionOpinion()
  436. {
  437. $userManager = $this->getUserManager();
  438. $userCurrent = $this->getUserCurrent();
  439. $model = new OpinionForm();
  440. $opinionSent = false;
  441. if ($model->load(Yii::$app->request->post()) && $model->validate()) {
  442. // @TODO : placer l'envoi de l'email dans un service dédié
  443. \Yii::$app->mailerService->sendAdmin(
  444. 'Nouvel avis',
  445. 'newOpinionAdmin',
  446. [
  447. 'username' => $userCurrent ? $userManager->getUsername($userCurrent) : $model->name,
  448. 'message' => $model->message,
  449. ],
  450. $userCurrent ? $userCurrent->email : $model->email
  451. );
  452. $opinionSent = true;
  453. }
  454. return $this->render('opinion', [
  455. 'model' => $model,
  456. 'opinionSent' => $opinionSent
  457. ]);
  458. }
  459. /**
  460. * Affiche les mentions légales.
  461. */
  462. public function actionMentions()
  463. {
  464. return $this->render('mentions');
  465. }
  466. /**
  467. * Affiche les conditions générale de service.
  468. */
  469. public function actionCgv()
  470. {
  471. return $this->render('cgv');
  472. }
  473. /**
  474. * Affiche les précisions concernant l'utilisation du crédit.
  475. */
  476. public function actionCredit()
  477. {
  478. return $this->render('credit');
  479. }
  480. }