BxMassMailerModule.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup MassMailer Mass Mailer
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. class BxMassMailerModule extends BxBaseModGeneralModule
  12. {
  13. private $aSegments = array();
  14. function __construct(&$aModule)
  15. {
  16. parent::__construct($aModule);
  17. $CNF = &$this->_oConfig->CNF;
  18. $aRv = array('lvl:0' => _t('_bx_massmailer_segments_all'));
  19. $oAccountQuery = BxDolAclQuery::getInstance();
  20. $aTmp = array();
  21. $oAccountQuery->getLevels(array('type' => 'all_active_pair'), $aTmp);
  22. foreach ($aTmp as $sKey => $sTmp){
  23. if ($sKey != MEMBERSHIP_ID_NON_MEMBER && $sKey != MEMBERSHIP_ID_ACCOUNT)
  24. $aRv['lvl:' . $sKey] = _t($sTmp);
  25. };
  26. $aTmp = $this->_oDb->getSegments();
  27. foreach ($aTmp as $sKey => $sTmp){
  28. $aRv['cst:' . $sKey] = _t($sTmp);
  29. };
  30. $this->aSegments = $aRv;
  31. }
  32. /**
  33. * ACTION METHODS
  34. */
  35. public function actionTrack($sActionName, $sHash)
  36. {
  37. if (isset($sHash) && trim($sHash) != ""){
  38. switch ($sActionName) {
  39. case 'click':
  40. $sLink = $this->_oDb->updateDateClickForLink($sHash);
  41. if (strpos($sLink, '://') === false)
  42. $sLink = BX_DOL_URL_ROOT . $sLink;
  43. header('Location: ' . $sLink);
  44. break;
  45. case 'seen':
  46. header('Content-Type: image/png');
  47. $this->_oDb->updateDateSeenForLetter($sHash);
  48. break;
  49. }
  50. }
  51. }
  52. public function actionGetReportsData($sReportName, $sReportType, $sDateFrom, $sDateTo, $sSegment)
  53. {
  54. if($this->checkAllowed() !== CHECK_ACTION_RESULT_ALLOWED)
  55. return '';
  56. header('Content-Type: application/json');
  57. $aColors = array('#3366CC', '#DC3912', '#FF9900', '#109618', '#990099');
  58. $iDateFrom = strtotime($sDateFrom);
  59. $iDateTo = strtotime($sDateTo);
  60. $sType = "bar";
  61. $bIsTimeX = false;
  62. $iMinValueY = 0;
  63. $iMaxValueY = 0;
  64. $aValues = array('labels' => array(), 'values' => array(array('legend' => '', 'data' => array())), 'links' => array(), 'strings' => array(0 => _t('_bx_massmailer_txt_item'), 1 => _t('_bx_massmailer_txt_value')));
  65. switch ($sReportName) {
  66. case "SUBSCRIBERS_INFO":
  67. $sType = "line";
  68. $bIsTimeX = true;
  69. $aValues['strings'][0] = _t('_bx_massmailer_txt_date');
  70. $aValues['strings'][1] = '';
  71. $sSql = $this->getSqlBySegment($sSegment);
  72. $aData = $this->_oDb->getAccountsByTermsStat($iDateFrom, $iDateTo, $sSql);
  73. $aData2 = $this->_oDb->getAccountsByTermsStatUnsubscribe($iDateFrom, $iDateTo, $sSql);
  74. $iValuePrev = $this->_oDb->getAccountsByTermsStatInitValue($iDateFrom, $sSql);
  75. $iValuePrev2 = $this->_oDb->getAccountsByTermsStatInitValueUnsubscribe($iDateFrom, $sSql);
  76. $aTmpDates = array();
  77. $aTmpDates2 = array();
  78. $aValues['values'][0]['legend'] = _t('_bx_massmailer_txt_subscribed');
  79. $aValues['values'][1] = array('legend' => _t('_bx_massmailer_txt_unsubscribed') , 'data' => array());
  80. foreach ($aData as $aValue) {
  81. $aTmpDates[$aValue['period']] = $aValue['count'];
  82. }
  83. foreach ($aData2 as $aValue) {
  84. $aTmpDates2[$aValue['period']] = $aValue['count'];
  85. }
  86. for ($i = $iDateFrom; $i < $iDateTo ; $i = $i + 86400 ){
  87. $sX = date('Y-m-d', $i);
  88. if (!array_key_exists($sX, $aTmpDates)){
  89. array_push($aValues['values'][0]['data'], array('x' => $sX, 'y' => $sReportType == 'content_total' ? $iValuePrev : 0));
  90. }
  91. else{
  92. array_push($aValues['values'][0]['data'], array('x' => $sX, 'y' => $sReportType == 'content_total' ? $iValuePrev : $aTmpDates[$sX]));
  93. $iValuePrev += $aTmpDates[$sX];
  94. }
  95. if (!array_key_exists($sX, $aTmpDates2)){
  96. array_push($aValues['values'][1]['data'], array('x' => $sX, 'y' => $sReportType == 'content_total' ? $iValuePrev2 : 0));
  97. }
  98. else{
  99. array_push($aValues['values'][1]['data'], array('x' => $sX, 'y' => $sReportType == 'content_total' ? $iValuePrev2 : $aTmpDates2[$sX]));
  100. $iValuePrev2 += $aTmpDates2[$sX];
  101. }
  102. if ($sReportType == 'content_total'){
  103. if ($iValuePrev > $iMaxValueY)
  104. $iMaxValueY = $iValuePrev;
  105. if ($iValuePrev2 > $iMaxValueY)
  106. $iMaxValueY = $iValuePrev2;
  107. }
  108. else{
  109. if (array_key_exists($sX, $aTmpDates) && $aTmpDates[$sX] > $iMaxValueY)
  110. $iMaxValueY = $aTmpDates[$sX];
  111. if (array_key_exists($sX, $aTmpDates2) && $aTmpDates2[$sX] > $iMaxValueY)
  112. $iMaxValueY = $aTmpDates2[$sX];
  113. }
  114. }
  115. break;
  116. case "CAMPAIGN_REPORT":
  117. $aDataStat = $this->_oDb->getStatByCampaignId($sReportType);
  118. $aValues['values'][0]['legend'] = _t('_bx_massmailer_txt_sent_total_title', $aDataStat['total']);
  119. array_push($aValues['values'][0]['data'], $aDataStat['total']);
  120. $aValues['values'][1] = array('legend' => _t('_bx_massmailer_txt_opened_total_title', $aDataStat['seen']) , 'data' => array($aDataStat['seen']));
  121. $aValues['values'][2] = array('legend' => _t('_bx_massmailer_txt_unopened_total_title', $aDataStat['total'] - $aDataStat['seen']), 'data' => array($aDataStat['total'] - $aDataStat['seen']));
  122. $aValues['values'][3] = array('legend' => _t('_bx_massmailer_txt_clicked_total_title', $aDataStat['clicked']), 'data' => array($aDataStat['clicked']));
  123. $aValues['values'][4] = array('legend' => _t('_bx_massmailer_txt_unsubscribed_total_title', $aDataStat['unsubscribed']), 'data' => array($aDataStat['unsubscribed']));
  124. $iMaxValueY = $aDataStat['total'];
  125. break;
  126. }
  127. $iMaxValueY = ceil($iMaxValueY * 1.1);
  128. $aDataForChartXAxes = array();
  129. if ($bIsTimeX){
  130. $sUnit = 'day';
  131. $iInterval = ($iDateTo - $iDateFrom) / 86400;
  132. if ($iInterval > 50)
  133. $sUnit = 'week';
  134. if ($iInterval > 100)
  135. $sUnit = 'month';
  136. $aDataForChartXAxes = array(
  137. 'type' => 'time',
  138. 'time' => array(
  139. 'tooltipFormat' => 'DD.MM.YYYY',
  140. 'unit' => $sUnit,
  141. ),
  142. 'display' => true,
  143. 'distribution' => 'linear',
  144. 'ticks' => array(
  145. 'display' => true,
  146. 'autoSkip' => true,
  147. )
  148. );
  149. }
  150. else{
  151. $aDataForChartXAxes = array(
  152. 'ticks' => array(
  153. 'autoSkip' => false
  154. ),
  155. 'display' => true
  156. );
  157. }
  158. $aDataForChartDatasets = array();
  159. for($i = 0; $i < count($aValues['values']); $i++){
  160. $aDataForChartDatasets[] = array(
  161. 'label' => $aValues['values'][$i]['legend'],
  162. 'fill' => false,
  163. 'backgroundColor' => $aColors[$i],
  164. 'borderColor' => $aColors[$i],
  165. 'borderWidth' => 1,
  166. 'data' => $aValues['values'][$i]['data']
  167. );
  168. }
  169. $aDataForChart = array(
  170. 'type' => $sType,
  171. 'data' => array(
  172. 'labels' => $aValues['labels'],
  173. 'datasets' => $aDataForChartDatasets
  174. ),
  175. 'options' => array(
  176. 'legend' => array(
  177. 'position' => 'bottom',
  178. 'display' => count($aValues['values']) == 1 ? false : true
  179. ),
  180. 'scales' => array(
  181. 'yAxes' => array(
  182. array(
  183. 'ticks' => array(
  184. 'max' => $iMaxValueY,
  185. 'min' => $iMinValueY,
  186. 'stepSize' => $this->getReportStep($iMinValueY, $iMaxValueY),
  187. 'autoSkip' => true
  188. )
  189. )
  190. ),
  191. 'xAxes' => array($aDataForChartXAxes)
  192. )
  193. ),
  194. 'links' => $aValues['links'],
  195. 'strings' => $aValues['strings'],
  196. );
  197. echo json_encode($aDataForChart);
  198. }
  199. /**
  200. * SERVICE METHODS
  201. */
  202. public function serviceGetSafeServices()
  203. {
  204. return array ();
  205. }
  206. /**
  207. * @page service Service Calls
  208. * @section bx_massmailer Mass mailer
  209. * @subsection bx_massmailer-page_blocks Page Blocks
  210. * @subsubsection bx_massmailer-campagn_subscribers campagn_subscribers
  211. *
  212. * @code bx_srv('bx_massmailer', 'campagn_subscribers', [...]); @endcode
  213. *
  214. * Get page block with the campagn's subscribers list
  215. *
  216. * @param $iContentId content ID.
  217. * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  218. *
  219. * @see BxMassMailerModule::serviceCampagnSubscribers
  220. */
  221. /**
  222. * @ref bx_massmailer-campagn_subscribers "entity_view"
  223. */
  224. public function serviceCampagnSubscribers ($iContentId = 0, $sDisplay = false)
  225. {
  226. if(!$iContentId)
  227. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  228. if(!$iContentId)
  229. return false;
  230. $aData = $this->_oDb->getLettersByCampaignId($iContentId);
  231. if (count($aData) > 0)
  232. return $this->_oTemplate->getSubscribers($aData);
  233. return $iContentId;
  234. }
  235. /**
  236. * @page service Service Calls
  237. * @section bx_massmailer Mass mailer
  238. * @subsection bx_massmailer-page_blocks Page Blocks
  239. * @subsubsection bx_massmailer-campagn_info campagn_info
  240. *
  241. * @code bx_srv('bx_massmailer', 'campagn_info', [...]); @endcode
  242. *
  243. * Get page block with the campagn info
  244. *
  245. * @param $iContentId content ID.
  246. * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  247. *
  248. * @see BxMassMailerModule::serviceCampagnInfo
  249. */
  250. /**
  251. * @ref bx_massmailer-campagn_info "campagn_info"
  252. */
  253. public function serviceCampagnInfo ($iContentId = 0, $sDisplay = false)
  254. {
  255. if(!$iContentId)
  256. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  257. if(!$iContentId)
  258. return false;
  259. return $this->_oTemplate->getInfo($iContentId);
  260. }
  261. /**
  262. * @page service Service Calls
  263. * @section bx_massmailer Mass mailer
  264. * @subsection bx_massmailer-page_blocks Page Blocks
  265. * @subsubsection bx_massmailer-campagn_links campagn_links
  266. *
  267. * @code bx_srv('bx_massmailer', 'campagn_links', [...]); @endcode
  268. *
  269. * Get page block with the campagn links list
  270. *
  271. * @param $iContentId content ID
  272. * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  273. *
  274. * @see BxMassMailerModule::serviceCampagnLinks
  275. */
  276. /**
  277. * @ref bx_massmailer-campagn_links "campagn_links"
  278. */
  279. public function serviceCampagnLinks ($iContentId = 0, $sDisplay = false)
  280. {
  281. if(!$iContentId)
  282. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  283. if(!$iContentId)
  284. return false;
  285. $aData = $this->_oDb->getClicksByCampaignId($iContentId);
  286. if (count($aData) > 0)
  287. return $this->_oTemplate->getClicks($aData);
  288. return $iContentId;
  289. }
  290. /**
  291. * @page service Service Calls
  292. * @section bx_massmailer Mass mailer
  293. * @subsection bx_massmailer-page_blocks Page Blocks
  294. * @subsubsection bx_massmailer-total_subscribers total_subscribers
  295. *
  296. * @code bx_srv('bx_massmailer', 'total_subscribers', [...]); @endcode
  297. *
  298. * Get page block with subscribers charts
  299. *
  300. * @param $aParams an array with search params.
  301. * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  302. *
  303. * @see BxMassMailerModule::serviceTotalSubscribers
  304. */
  305. /**
  306. * @ref bx_massmailer-total_subscribers "total_subscribers"
  307. */
  308. public function serviceTotalSubscribers ()
  309. {
  310. if($this->checkAllowed() !== CHECK_ACTION_RESULT_ALLOWED)
  311. return '';
  312. return $this->_oTemplate->getTotalSubscribers();
  313. }
  314. /**
  315. * @page service Service Calls
  316. * @section bx_massmailer Mass mailer
  317. * @subsection bx_massmailer-page_blocks Page Blocks
  318. * @subsubsection bx_massmailer-entity_breadcrumb entity_breadcrumb
  319. *
  320. * @code bx_srv('bx_massmailer', 'entity_breadcrumb', [...]); @endcode
  321. *
  322. * Get page block with page's breadcrumbs
  323. *
  324. * @param $iContentId content ID
  325. * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  326. *
  327. * @see BxMassMailerModule::serviceEntityBreadcrumb
  328. */
  329. /**
  330. * @ref bx_massmailer-entity_breadcrumb "entity_breadcrumb"
  331. */
  332. public function serviceEntityBreadcrumb ($iContentId = 0)
  333. {
  334. $CNF = &$this->_oConfig->CNF;
  335. $oPermalink = BxDolPermalinks::getInstance();
  336. if (!$iContentId)
  337. $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
  338. if (!$iContentId){
  339. $aContentInfo[$CNF['FIELD_TITLE']] = _t('_bx_massmailer_txt_breadcrumb_title_new_campaign');
  340. $aContentInfo['url'] = $oPermalink->permalink('page.php?i=' . $CNF['URI_ADD_CAMPAIGN']);
  341. }
  342. else{
  343. $aContentInfo = $this->_oDb->getCampaignInfoById($iContentId);
  344. if (!$aContentInfo)
  345. return false;
  346. $aContentInfo['url'] = $oPermalink->permalink('page.php?i=' . $CNF['URI_VIEW_CAMPAIGN'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]);
  347. }
  348. return $this->_oTemplate->entryBreadcrumb($aContentInfo);
  349. }
  350. /**
  351. * @page service Service Calls
  352. * @section bx_massmailer Mass mailer
  353. * @subsection bx_massmailer-page_blocks Page Blocks
  354. * @subsubsection bx_massmailer-attributes attributes
  355. *
  356. * @code bx_srv('bx_massmailer', 'attributes', [...]); @endcode
  357. *
  358. * Get page block with attributes list
  359. *
  360. * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
  361. *
  362. * @see BxMassMailerModule::serviceAttributes
  363. */
  364. /**
  365. * @ref bx_massmailer-attributes "attributes"
  366. */
  367. public function serviceAttributes ()
  368. {
  369. $aAttributesParts = array();
  370. $aAttributesParts['account'] = array(
  371. _t('_bx_massmailer_txt_attribute_global'),
  372. array(
  373. 'email' => _t('_bx_massmailer_txt_attribute_email'),
  374. 'account_name' => _t('_bx_massmailer_txt_attribute_account_name'),
  375. 'account_id' => _t('_bx_massmailer_txt_attribute_account_id'),
  376. 'reset_password_url' => _t('_bx_massmailer_txt_attribute_reset_password_url'),
  377. 'unsubscribe_url' => _t('_bx_massmailer_txt_attribute_unsubscribe_url')
  378. )
  379. );
  380. $BxDolModuleQuery = BxDolModuleQuery::getInstance();
  381. $aModules = $BxDolModuleQuery->getModulesBy(array('type' => 'modules', 'active' => 1));
  382. foreach($aModules as $aModule){
  383. if(BxDolRequest::serviceExists($aModule['name'], 'act_as_profile') && BxDolService::call($aModule['name'], 'act_as_profile') == true){
  384. $oModule = BxDolModule::getInstance($aModule['name']);
  385. $aTmp2 = array();
  386. $aTmp = $oModule->serviceGetSearchableFieldsExtended('view');
  387. foreach($aTmp as $sKey => $aField){
  388. $aTmp2[$sKey] = _t($aField['caption']);
  389. }
  390. $aAttributesParts[$aModule['name']] = array($aModule['title'], $aTmp2);
  391. }
  392. }
  393. return $this->_oTemplate->getAttributes($aAttributesParts);
  394. }
  395. /**
  396. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  397. */
  398. public function checkAllowedAdd ($isPerformAction = false)
  399. {
  400. return $this->checkAllowed($isPerformAction);
  401. }
  402. /**
  403. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  404. */
  405. public function checkAllowedEdit ($aDataEntry, $isPerformAction = false)
  406. {
  407. return $this->checkAllowed($isPerformAction);
  408. }
  409. /**
  410. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  411. */
  412. public function checkAllowedEditAnyEntryForProfile ($isPerformAction = false, $iProfileId = false)
  413. {
  414. return $this->checkAllowed($isPerformAction);
  415. }
  416. /**
  417. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  418. */
  419. public function checkAllowedDelete (&$aDataEntry, $isPerformAction = false)
  420. {
  421. return $this->checkAllowed($isPerformAction);
  422. }
  423. public function getSegments($sKey = "")
  424. {
  425. if ($sKey == ""){
  426. return $this->aSegments;
  427. }
  428. else{
  429. if (isset($this->aSegments[$sKey]))
  430. return $this->aSegments[$sKey];
  431. return false;
  432. }
  433. }
  434. public function sendTest($sEmail, $iCampaignId)
  435. {
  436. $aTmp = $this->getDataForCampaign($iCampaignId);
  437. $aTemplate = $aTmp[0];
  438. $aCustomHeaders = $aTmp[1];
  439. $aCampaign = $aTmp[2];
  440. if (!$aTemplate)
  441. return false;
  442. return $this->sendLetter($sEmail, $iCampaignId, $aCustomHeaders, getLoggedId(), $aTemplate, false, $aCampaign['is_track_links']);
  443. }
  444. public function sendAll($iCampaignId)
  445. {
  446. $aTmp = $this->getDataForCampaign($iCampaignId);
  447. $aTemplate = $aTmp[0];
  448. $aCustomHeaders = $aTmp[1];
  449. $aCampaign = $aTmp[2];
  450. if (!$aTemplate)
  451. return false;
  452. $GLOBALS['bx_profiler_disable'] = true;
  453. unset($GLOBALS['bx_profiler']);
  454. $this->_oDb->deleteCampaignData($iCampaignId);
  455. $aAccounts = $this->getEmailsBySegment($aCampaign['segments'], $aCampaign['is_one_per_account']);
  456. foreach ($aAccounts as $aAccountInfo){
  457. $this->sendLetter($aAccountInfo['email'], $iCampaignId, $aCustomHeaders, $aAccountInfo['account_id'], $aTemplate, true, $aCampaign['is_track_links']);
  458. $this->_oDb->addEmailToSentListForCampaign($iCampaignId, $aAccountInfo['email']);
  459. if (1 == rand(1, 300)) {
  460. BxDolDb::getInstance()->cleanMemoryAll();
  461. unset($GLOBALS['bxDolClasses']);
  462. }
  463. }
  464. $this->_oDb->sendCampaign($iCampaignId);
  465. return true;
  466. }
  467. private function sendLetter($sEmail, $iCampaignId, $aCustomHeaders, $iAccountId, $aTemplate, $bAddToQueue, $bTrackKinks)
  468. {
  469. $sLetterCode = $this->_oDb->addLetter($iCampaignId, $sEmail);
  470. $aMarkers = $this->addMarkers($iAccountId, $sLetterCode);
  471. bx_alert($this->_aModule['name'], 'user_fields', $iCampaignId, $iAccountId, array('email' => $sEmail, 'markers' => &$aMarkers, 'markers_ref' => &$aMarkers));
  472. if ($bTrackKinks){
  473. $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
  474. $aTemplate['Body'] = preg_replace_callback("/$regexp/siU",
  475. function ($aMatch) use ($iCampaignId, $sLetterCode, $aMarkers) {
  476. if ($aMatch[2] != '{unsubscribe_url}'){
  477. $sUrl = bx_replace_markers($aMatch[2], $aMarkers);
  478. $sLinkCode = $this->_oDb->addLink($sLetterCode, $sUrl, $aMatch[3], $iCampaignId);
  479. return str_replace($sUrl, BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'track/click/' . $sLinkCode . "/", $aMatch[0]);
  480. }
  481. else{
  482. return $aMatch[0];
  483. }
  484. },
  485. $aTemplate['Body']);
  486. }
  487. $aMarkersInLetter = [];
  488. preg_match_all("/\{[^\}]*\}/i", $aTemplate['Body'], $aMarkersInLetter);
  489. if ($aMarkersInLetter[0]>0){
  490. foreach ($aMarkersInLetter[0] as $sMarker){
  491. $sMarker = str_replace(['{', '}'], '', $sMarker);
  492. if (!array_key_exists($sMarker, $aMarkers)) {
  493. $aMarkers[$sMarker] = '';
  494. }
  495. }
  496. }
  497. return sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, $aMarkers, BX_EMAIL_MASS, 'html', false, $aCustomHeaders, $bAddToQueue);
  498. }
  499. public function getEmailCountInSegment($iCampaignId)
  500. {
  501. $aTmp = $this->getDataForCampaign($iCampaignId);
  502. $aCampaign = $aTmp[2];
  503. $aAccounts = $this->getEmailsBySegment($aCampaign['segments'], $aCampaign['is_one_per_account']);
  504. return count($aAccounts);
  505. }
  506. private function getEmailsBySegment($sSegment, $bIsOnePerAccount)
  507. {
  508. $sTerms = $this->getSqlBySegment($sSegment);
  509. if ($bIsOnePerAccount){
  510. $sTerms .= "AND `tp`.`id` = `ta`.`profile_id` ";
  511. }
  512. return $this->_oDb->getAccountsByTerms($sTerms);
  513. }
  514. public function checkAllowed($isPerformAction = false)
  515. {
  516. $aCheck = checkActionModule($this->_iProfileId, 'use massmailer', $this->getName(), $isPerformAction);
  517. if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
  518. return _t('_sys_txt_access_denied');
  519. return CHECK_ACTION_RESULT_ALLOWED;
  520. }
  521. private function getSqlBySegment($sSegment)
  522. {
  523. $sRv = '';
  524. $sJoin = ' INNER ';
  525. if (strpos($sSegment, 'lvl:') !== false){
  526. $sLvl = str_replace('lvl:', '', $sSegment);
  527. switch ($sLvl) {
  528. case 0:
  529. $sRv = '';
  530. $sJoin = ' LEFT ';
  531. break;
  532. case MEMBERSHIP_ID_UNCONFIRMED:
  533. $sRv = " AND `ta`.`email_confirmed` = 0 AND `ta`.`phone_confirmed` = 0 ";
  534. break;
  535. case MEMBERSHIP_ID_SUSPENDED:
  536. $sRv = " AND `tp`.`status` = 'suspended' ";
  537. break;
  538. case MEMBERSHIP_ID_PENDING:
  539. $sRv = " AND `tp`.`status` = 'pending' ";
  540. break;
  541. case MEMBERSHIP_ID_STANDARD:
  542. $sRv = " AND `tp`.`id` NOT IN (SELECT `IDMember` FROM `sys_acl_levels_members`) ";
  543. break;
  544. default:
  545. $sRv = $this->_oDb->prepareAsString(" AND `tp`.`id` IN (SELECT `IDMember` FROM `sys_acl_levels_members` WHERE IDLevel = ?) ", $sLvl);
  546. break;
  547. }
  548. $sRv .= " AND `tp`.`type` IN (" . $this->_oDb->implode_escape($this->getProfileModules()) . ")";
  549. }
  550. return $sJoin . " JOIN `sys_profiles` AS `tp` ON `tp`.`account_id`=`ta`.`id` " . $sRv;
  551. }
  552. private function getProfileModules()
  553. {
  554. $aResult = array();
  555. $BxDolModuleQuery = BxDolModuleQuery::getInstance();
  556. $aModules = $BxDolModuleQuery->getModulesBy(array('type' => 'modules', 'active' => 1));
  557. foreach($aModules as $aModule){
  558. if(BxDolRequest::serviceExists($aModule['name'], 'act_as_profile') && BxDolService::call($aModule['name'], 'act_as_profile') == true){
  559. array_push($aResult, $aModule['name']);
  560. }
  561. }
  562. return $aResult;
  563. }
  564. private function getDataForCampaign($iCampaignId)
  565. {
  566. $aCampaign = $this->_oDb->getCampaignInfoById($iCampaignId);
  567. $oEmailTemplates = BxDolEmailTemplates::getInstance();
  568. $aTemplate = $oEmailTemplates->parseTemplate('bx_massmailer_email', array('content' => $aCampaign['body']));
  569. $aTemplate['Subject'] = $aCampaign['subject'];
  570. $aCustomHeaders = array();
  571. $sFrom = $aCampaign['from_name'] != '' ? $aCampaign['from_name'] : getParam('site_title');
  572. $aCustomHeaders['From'] = "=?UTF-8?B?" . base64_encode($sFrom) . "?= <" . getParam('site_email_notify') . ">" ;
  573. if ($aCampaign['reply_to'] != ''){
  574. $sFrom = $aCampaign['from_name'] != '' ? $aCampaign['from_name'] : getParam('site_title');
  575. $aCustomHeaders['Reply-To'] = "=?UTF-8?B?" . base64_encode($sFrom) . '?= <' . bx_process_output($aCampaign['reply_to']) . '>';
  576. $aCustomHeaders['X-Original-From'] = "=?UTF-8?B?" . base64_encode($sFrom) . '?= <' . bx_process_output($aCampaign['reply_to']) . '>';
  577. }
  578. return array($aTemplate, $aCustomHeaders, $aCampaign);
  579. }
  580. private function addMarkers($iAccountId, $sLetterCode)
  581. {
  582. $CNF = &$this->_oConfig->CNF;
  583. $aMarkers = array();
  584. $oAccount = BxDolAccount::getInstance($iAccountId);
  585. $aAccountInfo = $oAccount->getInfo();
  586. $sAccountEmail = $oAccount->getEmail();
  587. $aMarkers['email'] = $sAccountEmail;
  588. $aMarkers['account_name'] = $oAccount->getDisplayName();
  589. $aMarkers['account_id'] = $oAccount->id();
  590. if ($aAccountInfo['profile_id'] > 0){
  591. $oProfile = BxDolProfile::getInstance($aAccountInfo['profile_id']);
  592. $sModule = $oProfile->getModule();
  593. if (BxDolRequest::serviceExists($sModule, 'get_info')) {
  594. $aProfileInfo = bx_srv($sModule, 'get_info', array($oProfile->getContentId(), false));
  595. foreach ($aProfileInfo as $sKey => $sValue)
  596. if(!isset($aMarkers[$sKey]))
  597. $aMarkers[$sKey] = $sValue;
  598. }
  599. }
  600. $aMarkers['seen_image_url'] = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'track/seen/' . $sLetterCode . "/";
  601. $aMarkers['unsubscribe_url'] = BX_DOL_URL_ROOT . $oAccount->getUnsubscribeLink(BX_EMAIL_MASS) . "&lhash=" . $sLetterCode;
  602. $aMarkers['reset_password_url'] = '';
  603. if(($sResetPasswordUrl = bx_get_reset_password_link($sAccountEmail)) !== false)
  604. $aMarkers['reset_password_url'] = $sResetPasswordUrl . "&lhash=" . $sLetterCode;
  605. return $aMarkers;
  606. }
  607. private function getReportStep($iMin, $iMax)
  608. {
  609. $iCount = 10;
  610. return ceil(($iMax - $iMin) / $iCount);
  611. }
  612. public function checkAllowedDeleteAnyEntryForProfile ($isPerformAction = false, $iProfileId = false)
  613. {
  614. return _t('_sys_txt_access_denied');
  615. }
  616. }
  617. /** @} */