vendor/pimcore/pimcore/bundles/AdminBundle/Controller/Admin/EmailController.php line 47

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Bundle\AdminBundle\Controller\Admin;
  15. use Pimcore\Bundle\AdminBundle\Controller\AdminAbstractController;
  16. use Pimcore\Http\RequestHelper;
  17. use Pimcore\Logger;
  18. use Pimcore\Mail;
  19. use Pimcore\Model\Element\ElementInterface;
  20. use Pimcore\Model\Tool;
  21. use Symfony\Component\HttpFoundation\JsonResponse;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\HttpKernel\Profiler\Profiler;
  25. use Symfony\Component\Mime\Address;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. /**
  28.  * @Route("/email")
  29.  *
  30.  * @internal
  31.  */
  32. class EmailController extends AdminAbstractController
  33. {
  34.     /**
  35.      * @Route("/email-logs", name="pimcore_admin_email_emaillogs", methods={"GET", "POST"})
  36.      *
  37.      * @param Request $request
  38.      *
  39.      * @return JsonResponse
  40.      *
  41.      * @throws \Exception
  42.      */
  43.     public function emailLogsAction(Request $request)
  44.     {
  45.         if (!$this->getAdminUser()->isAllowed('emails') && !$this->getAdminUser()->isAllowed('gdpr_data_extractor')) {
  46.             throw new \Exception("Permission denied, user needs 'emails' permission.");
  47.         }
  48.         $list = new Tool\Email\Log\Listing();
  49.         if ($request->get('documentId')) {
  50.             $list->setCondition('documentId = ' . (int)$request->get('documentId'));
  51.         }
  52.         $list->setLimit($request->get('limit'));
  53.         $list->setOffset($request->get('start'));
  54.         $list->setOrderKey('sentDate');
  55.         if ($request->get('filter')) {
  56.             $filterTerm $request->get('filter');
  57.             if ($filterTerm == '*') {
  58.                 $filterTerm '';
  59.             }
  60.             $filterTerm str_replace('%''*'$filterTerm);
  61.             $filterTerm htmlspecialchars($filterTermENT_QUOTES);
  62.             if (strpos($filterTerm'@')) {
  63.                 $parts explode(' '$filterTerm);
  64.                 $parts array_map(function ($part) {
  65.                     if (strpos($part'@')) {
  66.                         $part '"' $part '"';
  67.                     }
  68.                     return $part;
  69.                 }, $parts);
  70.                 $filterTerm implode(' '$parts);
  71.             }
  72.             $condition '( MATCH (`from`,`to`,`cc`,`bcc`,`subject`,`params`) AGAINST (' $list->quote($filterTerm) . ' IN BOOLEAN MODE) )';
  73.             if ($request->get('documentId')) {
  74.                 $condition .= 'AND documentId = ' . (int)$request->get('documentId');
  75.             }
  76.             $list->setCondition($condition);
  77.         }
  78.         $list->setOrder('DESC');
  79.         $data $list->load();
  80.         $jsonData = [];
  81.         if (is_array($data)) {
  82.             foreach ($data as $entry) {
  83.                 $tmp $entry->getObjectVars();
  84.                 unset($tmp['bodyHtml']);
  85.                 unset($tmp['bodyText']);
  86.                 $jsonData[] = $tmp;
  87.             }
  88.         }
  89.         return $this->adminJson([
  90.             'data' => $jsonData,
  91.             'success' => true,
  92.             'total' => $list->getTotalCount(),
  93.         ]);
  94.     }
  95.     /**
  96.      * @Route("/show-email-log", name="pimcore_admin_email_showemaillog", methods={"GET"})
  97.      *
  98.      * @param Request $request
  99.      * @param Profiler|null $profiler
  100.      *
  101.      * @return JsonResponse|Response
  102.      *
  103.      * @throws \Exception
  104.      */
  105.     public function showEmailLogAction(Request $request, ?Profiler $profiler)
  106.     {
  107.         if ($profiler) {
  108.             $profiler->disable();
  109.         }
  110.         if (!$this->getAdminUser()->isAllowed('emails')) {
  111.             throw $this->createAccessDeniedHttpException("Permission denied, user needs 'emails' permission.");
  112.         }
  113.         $type $request->get('type');
  114.         $emailLog Tool\Email\Log::getById((int) $request->get('id'));
  115.         if (!$emailLog) {
  116.             throw $this->createNotFoundException();
  117.         }
  118.         if ($type === 'text') {
  119.             return $this->render('@PimcoreAdmin/Admin/Email/text.html.twig', ['log' => $emailLog->getTextLog()]);
  120.         } elseif ($type === 'html') {
  121.             return new Response($emailLog->getHtmlLog(), 200, [
  122.                 'Content-Security-Policy' => "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src * data:",
  123.             ]);
  124.         } elseif ($type === 'params') {
  125.             try {
  126.                 $params $this->decodeJson($emailLog->getParams());
  127.             } catch (\Exception $e) {
  128.                 Logger::warning('Could not decode JSON param string');
  129.                 $params = [];
  130.             }
  131.             foreach ($params as &$entry) {
  132.                 $this->enhanceLoggingData($entry);
  133.             }
  134.             return $this->adminJson($params);
  135.         } elseif ($type === 'details') {
  136.             $data $emailLog->getObjectVars();
  137.             return $this->adminJson($data);
  138.         } else {
  139.             return new Response('No Type specified');
  140.         }
  141.     }
  142.     /**
  143.      * @param array $data
  144.      * @param array $fullEntry
  145.      */
  146.     protected function enhanceLoggingData(&$data, &$fullEntry null)
  147.     {
  148.         if (!empty($data['objectClass'])) {
  149.             $class '\\' ltrim($data['objectClass'], '\\');
  150.             $reflection = new \ReflectionClass($class);
  151.             if (!empty($data['objectId']) && $reflection->implementsInterface(ElementInterface::class)) {
  152.                 $obj $class::getById($data['objectId']);
  153.                 if (is_null($obj)) {
  154.                     $data['objectPath'] = '';
  155.                 } else {
  156.                     $data['objectPath'] = $obj->getRealFullPath();
  157.                 }
  158.                 //check for classmapping
  159.                 if (stristr($class'\\Pimcore\\Model') === false) {
  160.                     $niceClassName '\\' ltrim($reflection->getParentClass()->getName(), '\\');
  161.                 } else {
  162.                     $niceClassName $class;
  163.                 }
  164.                 $niceClassName str_replace('\\Pimcore\\Model\\'''$niceClassName);
  165.                 $niceClassName str_replace('_''\\'$niceClassName);
  166.                 $tmp explode('\\'$niceClassName);
  167.                 if (in_array($tmp[0], ['DataObject''Document''Asset'])) {
  168.                     $data['objectClassBase'] = $tmp[0];
  169.                     $data['objectClassSubType'] = $tmp[1];
  170.                 }
  171.             }
  172.         }
  173.         foreach ($data as &$value) {
  174.             if (is_array($value)) {
  175.                 $this->enhanceLoggingData($value$data);
  176.             }
  177.         }
  178.         if ($data['children'] ?? false) {
  179.             foreach ($data['children'] as $key => $entry) {
  180.                 if (is_string($key)) { //key must be integers
  181.                     unset($data['children'][$key]);
  182.                 }
  183.             }
  184.             $data['iconCls'] = 'pimcore_icon_folder';
  185.             $data['data'] = ['type' => 'simple''value' => 'Children (' count($data['children']) . ')'];
  186.         } else {
  187.             //setting the icon class
  188.             if (empty($data['iconCls'])) {
  189.                 if (($data['objectClassBase'] ?? '') == 'DataObject') {
  190.                     $fullEntry['iconCls'] = 'pimcore_icon_object';
  191.                 } elseif (($data['objectClassBase'] ?? '') == 'Asset') {
  192.                     switch ($data['objectClassSubType']) {
  193.                         case 'Image':
  194.                             $fullEntry['iconCls'] = 'pimcore_icon_image';
  195.                             break;
  196.                         case 'Video':
  197.                             $fullEntry['iconCls'] = 'pimcore_icon_wmv';
  198.                             break;
  199.                         case 'Text':
  200.                             $fullEntry['iconCls'] = 'pimcore_icon_txt';
  201.                             break;
  202.                         case 'Document':
  203.                             $fullEntry['iconCls'] = 'pimcore_icon_pdf';
  204.                             break;
  205.                         default:
  206.                             $fullEntry['iconCls'] = 'pimcore_icon_asset';
  207.                     }
  208.                 } elseif (strpos($data['objectClass'] ?? '''Document') === 0) {
  209.                     $fullEntry['iconCls'] = 'pimcore_icon_' strtolower($data['objectClassSubType']);
  210.                 } else {
  211.                     $data['iconCls'] = 'pimcore_icon_text';
  212.                 }
  213.             }
  214.             $data['leaf'] = true;
  215.         }
  216.     }
  217.     /**
  218.      * @Route("/delete-email-log", name="pimcore_admin_email_deleteemaillog", methods={"DELETE"})
  219.      *
  220.      * @param Request $request
  221.      *
  222.      * @return JsonResponse
  223.      *
  224.      * @throws \Exception
  225.      */
  226.     public function deleteEmailLogAction(Request $request)
  227.     {
  228.         if (!$this->getAdminUser()->isAllowed('emails')) {
  229.             throw $this->createAccessDeniedHttpException("Permission denied, user needs 'emails' permission.");
  230.         }
  231.         $success false;
  232.         $emailLog Tool\Email\Log::getById((int) $request->get('id'));
  233.         if ($emailLog instanceof Tool\Email\Log) {
  234.             $emailLog->delete();
  235.             $success true;
  236.         }
  237.         return $this->adminJson([
  238.             'success' => $success,
  239.         ]);
  240.     }
  241.     /**
  242.      * @Route("/resend-email", name="pimcore_admin_email_resendemail", methods={"POST"})
  243.      *
  244.      * @param Request $request
  245.      *
  246.      * @return JsonResponse
  247.      *
  248.      * @throws \Exception
  249.      */
  250.     public function resendEmailAction(Request $request)
  251.     {
  252.         if (!$this->getAdminUser()->isAllowed('emails')) {
  253.             throw $this->createAccessDeniedHttpException("Permission denied, user needs 'emails' permission.");
  254.         }
  255.         $success false;
  256.         $emailLog Tool\Email\Log::getById((int) $request->get('id'));
  257.         if ($emailLog instanceof Tool\Email\Log) {
  258.             $mail = new Mail();
  259.             $mail->preventDebugInformationAppending();
  260.             $mail->setIgnoreDebugMode(true);
  261.             if (!empty($request->get('to'))) {
  262.                 $emailLog->setTo(null);
  263.                 $emailLog->setCc(null);
  264.                 $emailLog->setBcc(null);
  265.             } else {
  266.                 $mail->disableLogging();
  267.             }
  268.             if ($html $emailLog->getHtmlLog()) {
  269.                 $mail->html($html);
  270.             }
  271.             if ($text $emailLog->getTextLog()) {
  272.                 $mail->text($text);
  273.             }
  274.             foreach (['From''To''Cc''Bcc''ReplyTo'] as $field) {
  275.                 if (!$values $request->get(strtolower($field))) {
  276.                     $getter 'get' $field;
  277.                     $values $emailLog->{$getter}();
  278.                 }
  279.                 $values \Pimcore\Helper\Mail::parseEmailAddressField($values);
  280.                 if (!empty($values)) {
  281.                     list($value) = $values;
  282.                     if ($value) {
  283.                         $prefix 'add';
  284.                         $mail->{$prefix $field}(new Address($value['email'], $value['name'] ?? ''));
  285.                     }
  286.                 }
  287.             }
  288.             $mail->subject($emailLog->getSubject());
  289.             // add document
  290.             if ($emailLog->getDocumentId()) {
  291.                 $mail->setDocument($emailLog->getDocumentId());
  292.             }
  293.             // re-add params
  294.             try {
  295.                 $params $this->decodeJson($emailLog->getParams());
  296.             } catch (\Exception $e) {
  297.                 Logger::warning('Could not decode JSON param string');
  298.                 $params = [];
  299.             }
  300.             foreach ($params as $entry) {
  301.                 $data null;
  302.                 $hasChildren = isset($entry['children']) && is_array($entry['children']);
  303.                 if ($hasChildren) {
  304.                     $childData = [];
  305.                     foreach ($entry['children'] as $childParam) {
  306.                         $childData[$childParam['key']] = $this->parseLoggingParamObject($childParam);
  307.                     }
  308.                     $data $childData;
  309.                 } else {
  310.                     $data $this->parseLoggingParamObject($entry);
  311.                 }
  312.                 $mail->setParam($entry['key'], $data);
  313.             }
  314.             $mail->send();
  315.             $success true;
  316.         }
  317.         return $this->adminJson([
  318.             'success' => $success,
  319.         ]);
  320.     }
  321.     /**
  322.      * @Route("/send-test-email", name="pimcore_admin_email_sendtestemail", methods={"POST"})
  323.      *
  324.      * @param Request $request
  325.      *
  326.      * @return JsonResponse
  327.      *
  328.      * @throws \Exception
  329.      */
  330.     public function sendTestEmailAction(Request $request)
  331.     {
  332.         if (!$this->getAdminUser()->isAllowed('emails')) {
  333.             throw new \Exception("Permission denied, user needs 'emails' permission.");
  334.         }
  335.         // Simulate a frontend request to prefix assets
  336.         $request->attributes->set(RequestHelper::ATTRIBUTE_FRONTEND_REQUESTtrue);
  337.         $mail = new Mail();
  338.         if ($request->get('emailType') == 'text') {
  339.             $mail->text($request->get('content'));
  340.         } elseif ($request->get('emailType') == 'html') {
  341.             $mail->html($request->get('content'));
  342.         } elseif ($request->get('emailType') == 'document') {
  343.             $doc \Pimcore\Model\Document::getByPath($request->get('documentPath'));
  344.             if ($doc instanceof \Pimcore\Model\Document\Email || $doc instanceof \Pimcore\Model\Document\Newsletter) {
  345.                 $mail->setDocument($doc);
  346.                 if ($request->get('mailParamaters')) {
  347.                     if ($mailParamsArray json_decode($request->get('mailParamaters'), true)) {
  348.                         foreach ($mailParamsArray as $mailParam) {
  349.                             if ($mailParam['key']) {
  350.                                 $mail->setParam($mailParam['key'], $mailParam['value']);
  351.                             }
  352.                         }
  353.                     }
  354.                 }
  355.             } else {
  356.                 throw new \Exception('Email document not found!');
  357.             }
  358.         }
  359.         if ($from $request->get('from')) {
  360.             $addressArray \Pimcore\Helper\Mail::parseEmailAddressField($from);
  361.             if ($addressArray) {
  362.                 //use the first address only
  363.                 list($cleanedFromAddress) = $addressArray;
  364.                 $mail->from(new Address($cleanedFromAddress['email'], $cleanedFromAddress['name'] ?? ''));
  365.             }
  366.         }
  367.         $toAddresses \Pimcore\Helper\Mail::parseEmailAddressField($request->get('to'));
  368.         foreach ($toAddresses as $cleanedToAddress) {
  369.             $mail->addTo($cleanedToAddress['email'], $cleanedToAddress['name'] ?? '');
  370.         }
  371.         $mail->subject($request->get('subject'));
  372.         $mail->setIgnoreDebugMode(true);
  373.         $mail->send();
  374.         return $this->adminJson([
  375.             'success' => true,
  376.         ]);
  377.     }
  378.     /**
  379.      * @Route("/blocklist", name="pimcore_admin_email_blocklist", methods={"POST"})
  380.      *
  381.      * @param Request $request
  382.      *
  383.      * @return JsonResponse
  384.      *
  385.      * @throws \Exception
  386.      */
  387.     public function blocklistAction(Request $request)
  388.     {
  389.         if (!$this->getAdminUser()->isAllowed('emails')) {
  390.             throw new \Exception("Permission denied, user needs 'emails' permission.");
  391.         }
  392.         if ($request->get('data')) {
  393.             $data $this->decodeJson($request->get('data'));
  394.             if (is_array($data)) {
  395.                 foreach ($data as $key => &$value) {
  396.                     if (is_string($value)) {
  397.                         if ($key === 'address') {
  398.                             $value filter_var($valueFILTER_SANITIZE_EMAIL);
  399.                         }
  400.                         $value trim($value);
  401.                     }
  402.                 }
  403.             }
  404.             if ($request->get('xaction') == 'destroy') {
  405.                 $address Tool\Email\Blocklist::getByAddress($data['address']);
  406.                 $address->delete();
  407.                 return $this->adminJson(['success' => true'data' => []]);
  408.             } elseif ($request->get('xaction') == 'update') {
  409.                 $address Tool\Email\Blocklist::getByAddress($data['address']);
  410.                 $address->setValues($data);
  411.                 $address->save();
  412.                 return $this->adminJson(['data' => $address->getObjectVars(), 'success' => true]);
  413.             } elseif ($request->get('xaction') == 'create') {
  414.                 unset($data['id']);
  415.                 $address = new Tool\Email\Blocklist();
  416.                 $address->setValues($data);
  417.                 $address->save();
  418.                 return $this->adminJson(['data' => $address->getObjectVars(), 'success' => true]);
  419.             }
  420.         } else {
  421.             // get list of routes
  422.             $list = new Tool\Email\Blocklist\Listing();
  423.             $list->setLimit($request->get('limit'));
  424.             $list->setOffset($request->get('start'));
  425.             $sortingSettings \Pimcore\Bundle\AdminBundle\Helper\QueryParams::extractSortingSettings($request->query->all());
  426.             if ($sortingSettings['orderKey']) {
  427.                 $orderKey $sortingSettings['orderKey'];
  428.             }
  429.             if ($sortingSettings['order']) {
  430.                 $order $sortingSettings['order'];
  431.             }
  432.             if ($request->get('filter')) {
  433.                 $list->setCondition('`address` LIKE ' $list->quote('%'.$request->get('filter').'%'));
  434.             }
  435.             $data $list->load();
  436.             $jsonData = [];
  437.             if (is_array($data)) {
  438.                 foreach ($data as $entry) {
  439.                     $jsonData[] = $entry->getObjectVars();
  440.                 }
  441.             }
  442.             return $this->adminJson([
  443.                 'success' => true,
  444.                 'data' => $jsonData,
  445.                 'total' => $list->getTotalCount(),
  446.             ]);
  447.         }
  448.         return $this->adminJson(['success' => false]);
  449.     }
  450.     /**
  451.      * @param array $params
  452.      *
  453.      * @return array
  454.      */
  455.     protected function parseLoggingParamObject($params)
  456.     {
  457.         $data null;
  458.         if ($params['data']['type'] === 'object') {
  459.             $class '\\' ltrim($params['data']['objectClass'], '\\');
  460.             $reflection = new \ReflectionClass($class);
  461.             if (!empty($params['data']['objectId']) && $reflection->implementsInterface(ElementInterface::class)) {
  462.                 $obj $class::getById($params['data']['objectId']);
  463.                 if (!is_null($obj)) {
  464.                     $data $obj;
  465.                 }
  466.             }
  467.         } else {
  468.             $data $params['data']['value'];
  469.         }
  470.         return $data;
  471.     }
  472. }