PageRenderTime 50ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/blocknewsletter/blocknewsletter.php

https://bitbucket.org/enurkov/prestashop
PHP | 519 lines | 347 code | 62 blank | 110 comment | 71 complexity | 2d3aaf2d015834beac5f5a21ff877b76 MD5 | raw file
  1. <?php
  2. /*
  3. * 2007-2012 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Academic Free License (AFL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/afl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2012 PrestaShop SA
  23. * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
  24. * International Registered Trademark & Property of PrestaShop SA
  25. */
  26. if (!defined('_PS_VERSION_'))
  27. exit;
  28. class Blocknewsletter extends Module
  29. {
  30. const GUEST_NOT_REGISTERED = -1;
  31. const CUSTOMER_NOT_REGISTERED = 0;
  32. const GUEST_REGISTERED = 1;
  33. const CUSTOMER_REGISTERED = 2;
  34. public function __construct()
  35. {
  36. $this->name = 'blocknewsletter';
  37. $this->tab = 'front_office_features';
  38. $this->need_instance = 0;
  39. parent::__construct();
  40. $this->displayName = $this->l('Newsletter block');
  41. $this->description = $this->l('Adds a block for newsletter subscription.');
  42. $this->confirmUninstall = $this->l('Are you sure you want to delete all your contacts ?');
  43. $this->version = '1.4';
  44. $this->author = 'PrestaShop';
  45. $this->error = false;
  46. $this->valid = false;
  47. $this->_files = array(
  48. 'name' => array('newsletter_conf', 'newsletter_voucher'),
  49. 'ext' => array(
  50. 0 => 'html',
  51. 1 => 'txt'
  52. )
  53. );
  54. }
  55. public function install()
  56. {
  57. if (parent::install() == false || $this->registerHook('leftColumn') == false || $this->registerHook('header') == false)
  58. return false;
  59. Configuration::updateValue('NW_SALT', Tools::passwdGen(16));
  60. return Db::getInstance()->execute('
  61. CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'newsletter` (
  62. `id` int(6) NOT NULL AUTO_INCREMENT,
  63. `id_shop` INTEGER UNSIGNED NOT NULL DEFAULT \'1\',
  64. `id_shop_group` INTEGER UNSIGNED NOT NULL DEFAULT \'1\',
  65. `email` varchar(255) NOT NULL,
  66. `newsletter_date_add` DATETIME NULL,
  67. `ip_registration_newsletter` varchar(15) NOT NULL,
  68. `http_referer` VARCHAR(255) NULL,
  69. `active` TINYINT(1) NOT NULL DEFAULT \'0\',
  70. PRIMARY KEY(`id`)
  71. ) ENGINE='._MYSQL_ENGINE_.' default CHARSET=utf8');
  72. }
  73. public function uninstall()
  74. {
  75. if (!parent::uninstall())
  76. return false;
  77. return Db::getInstance()->execute('DROP TABLE '._DB_PREFIX_.'newsletter');
  78. }
  79. public function getContent()
  80. {
  81. $this->_html = '<h2>'.$this->displayName.'</h2>';
  82. if (Tools::isSubmit('submitUpdate'))
  83. {
  84. if (isset($_POST['new_page']) && Validate::isBool((int)$_POST['new_page']))
  85. Configuration::updateValue('NW_CONFIRMATION_NEW_PAGE', $_POST['new_page']);
  86. if (isset($_POST['conf_email']) && Validate::isBool((int)$_POST['conf_email']))
  87. Configuration::updateValue('NW_CONFIRMATION_EMAIL', pSQL($_POST['conf_email']));
  88. if (isset($_POST['verif_email']) && Validate::isBool((int)$_POST['verif_email']))
  89. Configuration::updateValue('NW_VERIFICATION_EMAIL', (int)$_POST['verif_email']);
  90. if (!empty($_POST['voucher']) && !Validate::isDiscountName($_POST['voucher']))
  91. $this->_html .= '<div class="alert">'.$this->l('Voucher code is invalid').'</div>';
  92. else
  93. {
  94. Configuration::updateValue('NW_VOUCHER_CODE', pSQL($_POST['voucher']));
  95. $this->_html .= '<div class="conf ok">'.$this->l('Updated').'</div>';
  96. }
  97. }
  98. return $this->_displayForm();
  99. }
  100. private function _displayForm()
  101. {
  102. $this->_html .= '
  103. <form method="post" action="'.Tools::safeOutput($_SERVER['REQUEST_URI']).'">
  104. <fieldset>
  105. <legend><img src="'.$this->_path.'logo.gif" />'.$this->l('Settings').'</legend>
  106. <label>'.$this->l('Display configuration in a new page?').'</label>
  107. <div class="margin-form">
  108. <input type="radio" name="new_page" value="1" '.(Configuration::get('NW_CONFIRMATION_NEW_PAGE') ? 'checked="checked" ' : '').'/>'.$this->l('yes').'
  109. <input type="radio" name="new_page" value="0" '.(!Configuration::get('NW_CONFIRMATION_NEW_PAGE') ? 'checked="checked" ' : '').'/>'.$this->l('no').'
  110. </div>
  111. <div class="clear"></div>
  112. <label>'.$this->l('Send verification e-mail after subscription?').'</label>
  113. <div class="margin-form">
  114. <input type="radio" name="verif_email" value="1" '.(Configuration::get('NW_VERIFICATION_EMAIL') ? 'checked="checked" ' : '').'/>'.$this->l('yes').'
  115. <input type="radio" name="verif_email" value="0" '.(!Configuration::get('NW_VERIFICATION_EMAIL') ? 'checked="checked" ' : '').'/>'.$this->l('no').'
  116. </div>
  117. <div class="clear"></div>
  118. <label>'.$this->l('Send confirmation e-mail after subscription?').'</label>
  119. <div class="margin-form">
  120. <input type="radio" name="conf_email" value="1" '.(Configuration::get('NW_CONFIRMATION_EMAIL') ? 'checked="checked" ' : '').'/>'.$this->l('yes').'
  121. <input type="radio" name="conf_email" value="0" '.(!Configuration::get('NW_CONFIRMATION_EMAIL') ? 'checked="checked" ' : '').'/>'.$this->l('no').'
  122. </div>
  123. <div class="clear"></div>
  124. <label>'.$this->l('Welcome voucher code').'</label>
  125. <div class="margin-form">
  126. <input type="text" name="voucher" value="'.Configuration::get('NW_VOUCHER_CODE').'" />
  127. <p>'.$this->l('Leave blank for disabling').'</p>
  128. </div>
  129. <div class="margin-form clear pspace"><input type="submit" name="submitUpdate" value="'.$this->l('Update').'" class="button" /></div>
  130. </fieldset>
  131. </form>';
  132. return $this->_html;
  133. }
  134. /**
  135. * Check if this mail is registered for newsletters
  136. *
  137. * @param unknown_type $customerEmail
  138. * @return int -1 = not a customer and not registered
  139. * 0 = customer not registered
  140. * 1 = registered in block
  141. * 2 = registered in customer
  142. */
  143. private function isNewsletterRegistered($customerEmail)
  144. {
  145. $sql = 'SELECT `email`
  146. FROM '._DB_PREFIX_.'newsletter
  147. WHERE `email` = \''.pSQL($customerEmail).'\'
  148. AND id_shop = '.$this->context->shop->id;
  149. if (Db::getInstance()->getRow($sql))
  150. return self::GUEST_REGISTERED;
  151. $sql = 'SELECT `newsletter`
  152. FROM '._DB_PREFIX_.'customer
  153. WHERE `email` = \''.pSQL($customerEmail).'\'
  154. AND id_shop = '.$this->context->shop->id;
  155. if (!$registered = Db::getInstance()->getRow($sql))
  156. return self::GUEST_NOT_REGISTERED;
  157. if ($registered['newsletter'] == '1')
  158. return self::CUSTOMER_REGISTERED;
  159. return self::CUSTOMER_NOT_REGISTERED;
  160. }
  161. /**
  162. * Register in block newsletter
  163. */
  164. private function newsletterRegistration()
  165. {
  166. if (empty($_POST['email']) || !Validate::isEmail($_POST['email']))
  167. return $this->error = $this->l('Invalid e-mail address');
  168. /* Unsubscription */
  169. else if ($_POST['action'] == '1')
  170. {
  171. $register_status = $this->isNewsletterRegistered($_POST['email']);
  172. if ($register_status < 1)
  173. return $this->error = $this->l('E-mail address not registered');
  174. else if ($register_status == self::GUEST_REGISTERED)
  175. {
  176. if (!Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'newsletter WHERE `email` = \''.pSQL($_POST['email']).'\' AND id_shop = '.$this->context->shop->id))
  177. return $this->error = $this->l('Error during unsubscription');
  178. return $this->valid = $this->l('Unsubscription successful');
  179. }
  180. else if ($register_status == self::CUSTOMER_REGISTERED)
  181. {
  182. if (!Db::getInstance()->execute('UPDATE '._DB_PREFIX_.'customer SET `newsletter` = 0 WHERE `email` = \''.pSQL($_POST['email']).'\' AND id_shop = '.$this->context->shop->id))
  183. return $this->error = $this->l('Error during unsubscription');
  184. return $this->valid = $this->l('Unsubscription successful');
  185. }
  186. }
  187. /* Subscription */
  188. else if ($_POST['action'] == '0')
  189. {
  190. $register_status = $this->isNewsletterRegistered($_POST['email']);
  191. if ($register_status > 0)
  192. return $this->error = $this->l('E-mail address already registered');
  193. $email = pSQL($_POST['email']);
  194. if (!$this->isRegistered($register_status))
  195. {
  196. if (Configuration::get('NW_VERIFICATION_EMAIL'))
  197. {
  198. // create an unactive entry in the newsletter database
  199. if ($register_status == self::GUEST_NOT_REGISTERED)
  200. $this->registerGuest($email, false);
  201. if (!$token = $this->getToken($email, $register_status))
  202. return $this->error = $this->l('Error during subscription');
  203. $this->sendVerificationEmail($email, $token);
  204. return $this->valid = $this->l('A verification email has been sent. Please check your email.');
  205. }
  206. else
  207. {
  208. if ($this->register($email, $register_status))
  209. $this->valid = $this->l('Subscription successful');
  210. else
  211. return $this->error = $this->l('Error during subscription');
  212. if ($code = Configuration::get('NW_VOUCHER_CODE'))
  213. $this->sendVoucher($email, $code);
  214. if (Configuration::get('NW_CONFIRMATION_EMAIL'))
  215. $this->sendConfirmationEmail($email);
  216. }
  217. }
  218. }
  219. }
  220. /**
  221. * Return true if the registered status correspond to a registered user
  222. * @param int $register_status
  223. * @return bool
  224. */
  225. protected function isRegistered($register_status)
  226. {
  227. return in_array(
  228. $register_status,
  229. array(self::GUEST_REGISTERED, self::CUSTOMER_REGISTERED)
  230. );
  231. }
  232. /**
  233. * Subscribe an email to the newsletter. It will create an entry in the newsletter table
  234. * or update the customer table depending of the register status
  235. *
  236. * @param unknown_type $email
  237. * @param unknown_type $register_status
  238. */
  239. protected function register($email, $register_status)
  240. {
  241. if ($register_status == self::GUEST_NOT_REGISTERED)
  242. {
  243. if (!$this->registerGuest(Tools::getValue('email')))
  244. return false;
  245. }
  246. else if ($register_status == self::CUSTOMER_NOT_REGISTERED)
  247. {
  248. if (!$this->registerUser(Tools::getValue('email')))
  249. return false;
  250. }
  251. return true;
  252. }
  253. /**
  254. * Subscribe a customer to the newsletter
  255. *
  256. * @param string $email
  257. * @return bool
  258. */
  259. protected function registerUser($email)
  260. {
  261. $sql = 'UPDATE '._DB_PREFIX_.'customer
  262. SET `newsletter` = 1, newsletter_date_add = NOW(), `ip_registration_newsletter` = \''.pSQL(Tools::getRemoteAddr()).'\'
  263. WHERE `email` = \''.pSQL($email).'\'
  264. AND id_shop = '.$this->context->shop->id;
  265. return Db::getInstance()->execute($sql);
  266. }
  267. /**
  268. * Subscribe a guest to the newsletter
  269. *
  270. * @param string $email
  271. * @param bool $active
  272. * @return bool
  273. */
  274. protected function registerGuest($email, $active = true)
  275. {
  276. $sql = 'INSERT INTO '._DB_PREFIX_.'newsletter (id_shop, id_shop_group, email, newsletter_date_add, ip_registration_newsletter, http_referer, active)
  277. VALUES
  278. ('.$this->context->shop->id.',
  279. '.$this->context->shop->id_shop_group.',
  280. \''.pSQL($email).'\',
  281. NOW(),
  282. \''.pSQL(Tools::getRemoteAddr()).'\',
  283. (
  284. SELECT c.http_referer
  285. FROM '._DB_PREFIX_.'connections c
  286. WHERE c.id_guest = '.(int)$this->context->customer->id.'
  287. ORDER BY c.date_add DESC LIMIT 1
  288. ),
  289. '.(int)$active.'
  290. )';
  291. return Db::getInstance()->execute($sql);
  292. }
  293. public function activateGuest($email)
  294. {
  295. return Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'newsletter`
  296. SET `active` = 1
  297. WHERE `email` = \''.pSQL($email).'\''
  298. );
  299. }
  300. /**
  301. * Returns a guest email by token
  302. * @param string $token
  303. * @return string email
  304. */
  305. protected function getGuestEmailByToken($token)
  306. {
  307. $sql = 'SELECT `email`
  308. FROM `'._DB_PREFIX_.'newsletter`
  309. WHERE MD5(CONCAT( `email` , `newsletter_date_add`, \''.pSQL(Configuration::get('NW_SALT')).'\')) = \''.pSQL($token).'\'
  310. AND `active` = 0';
  311. return Db::getInstance()->getValue($sql);
  312. }
  313. /**
  314. * Returns a customer email by token
  315. * @param string $token
  316. * @return string email
  317. */
  318. protected function getUserEmailByToken($token)
  319. {
  320. $sql = 'SELECT `email`
  321. FROM `'._DB_PREFIX_.'customer`
  322. WHERE MD5(CONCAT( `email` , `date_add`, \''.pSQL(Configuration::get('NW_SALT')).'\')) = \''.pSQL($token).'\'
  323. AND `newsletter` = 0';
  324. return Db::getInstance()->getValue($sql);
  325. }
  326. /**
  327. * Return a token associated to an user
  328. *
  329. * @param string $email
  330. * @param string $register_status
  331. */
  332. protected function getToken($email, $register_status)
  333. {
  334. if (in_array($register_status, array(self::GUEST_NOT_REGISTERED, self::GUEST_REGISTERED)))
  335. {
  336. $sql = 'SELECT MD5(CONCAT( `email` , `newsletter_date_add`, \''.pSQL(Configuration::get('NW_SALT')).'\')) as token
  337. FROM `'._DB_PREFIX_.'newsletter`
  338. WHERE `active` = 0
  339. AND `email` = \''.pSQL($email).'\'';
  340. }
  341. else if ($register_status == self::CUSTOMER_NOT_REGISTERED)
  342. {
  343. $sql = 'SELECT MD5(CONCAT( `email` , `date_add`, \''.pSQL(Configuration::get('NW_SALT')).'\' )) as token
  344. FROM `'._DB_PREFIX_.'customer`
  345. WHERE `newsletter` = 0
  346. AND `email` = \''.pSQL($email).'\'';
  347. }
  348. return Db::getInstance()->getValue($sql);
  349. }
  350. /**
  351. * Ends the registration process to the newsletter
  352. *
  353. * @param string $token
  354. */
  355. public function confirmEmail($token)
  356. {
  357. $activated = false;
  358. if ($email = $this->getGuestEmailByToken($token))
  359. $activated = $this->activateGuest($email);
  360. else if ($email = $this->getUserEmailByToken($token))
  361. $activated = $this->registerUser($email);
  362. if (!$activated)
  363. return $this->l('Email already registered or invalid');
  364. if ($discount = Configuration::get('NW_VOUCHER_CODE'))
  365. $this->sendVoucher($email, $discount);
  366. if (Configuration::get('NW_CONFIRMATION_EMAIL'))
  367. $this->sendConfirmationEmail($email);
  368. return $this->l('Thank you for subscribing to our newsletter.');
  369. }
  370. /**
  371. * Send the confirmation mails to the given $email address if needed.
  372. *
  373. * @param string $email Email where to send the confirmation
  374. *
  375. * @note the email has been verified and might not yet been registered. Called by AuthController::processCustomerNewsletter
  376. *
  377. */
  378. public function confirmSubscription($email)
  379. {
  380. if ($email)
  381. {
  382. if ($discount = Configuration::get('NW_VOUCHER_CODE'))
  383. $this->sendVoucher($email, $discount);
  384. if (Configuration::get('NW_CONFIRMATION_EMAIL'))
  385. $this->sendConfirmationEmail($email);
  386. }
  387. }
  388. /**
  389. * Send an email containing a voucher code
  390. * @param string $email
  391. * @param string $discount
  392. * @return bool
  393. */
  394. protected function sendVoucher($email, $code)
  395. {
  396. return Mail::Send($this->context->language->id, 'newsletter_voucher', Mail::l('Newsletter voucher', $this->context->language->id), array('{discount}' => $code), $email, null, null, null, null, null, dirname(__FILE__).'/mails/');
  397. }
  398. /**
  399. * Send a confirmation email
  400. * @param string $email
  401. * @return bool
  402. */
  403. protected function sendConfirmationEmail($email)
  404. {
  405. return Mail::Send($this->context->language->id, 'newsletter_conf', Mail::l('Newsletter confirmation', $this->context->language->id), array(), pSQL($email), null, null, null, null, null, dirname(__FILE__).'/mails/');
  406. }
  407. /**
  408. * Send a verification email
  409. * @param string $email
  410. * @param string $token
  411. * @return bool
  412. */
  413. protected function sendVerificationEmail($email, $token)
  414. {
  415. $verif_url = Context::getContext()->link->getModuleLink('blocknewsletter', 'verification', array(
  416. 'token' => $token,
  417. ));
  418. return Mail::Send($this->context->language->id, 'newsletter_verif', Mail::l('Email verification', $this->context->language->id), array('{verif_url}' => $verif_url), $email, null, null, null, null, null, dirname(__FILE__).'/mails/');
  419. }
  420. public function hookDisplayRightColumn($params)
  421. {
  422. return $this->hookDisplayLeftColumn($params);
  423. }
  424. private function _prepareHook($params)
  425. {
  426. if (Tools::isSubmit('submitNewsletter'))
  427. {
  428. $this->newsletterRegistration();
  429. if ($this->error)
  430. {
  431. $this->smarty->assign(array('color' => 'red',
  432. 'msg' => $this->error,
  433. 'nw_value' => isset($_POST['email']) ? pSQL($_POST['email']) : false,
  434. 'nw_error' => true,
  435. 'action' => $_POST['action'])
  436. );
  437. }
  438. else if ($this->valid)
  439. {
  440. $this->smarty->assign(array('color' => 'green',
  441. 'msg' => $this->valid,
  442. 'nw_error' => false)
  443. );
  444. }
  445. }
  446. $this->smarty->assign('this_path', $this->_path);
  447. }
  448. public function hookDisplayLeftColumn($params)
  449. {
  450. $this->_prepareHook($params);
  451. return $this->display(__FILE__, 'blocknewsletter.tpl');
  452. }
  453. public function hookDisplayHeader($params)
  454. {
  455. $this->context->controller->addCSS($this->_path.'blocknewsletter.css', 'all');
  456. }
  457. }