diff --git a/Classes/Command/SendMailCommandController.php b/Classes/Command/SendMailCommandController.php index c2522604236c4ae171a507df607f7711f528ac28..d052eba5cf0692c9547ab5a317342564b50d3edf 100644 --- a/Classes/Command/SendMailCommandController.php +++ b/Classes/Command/SendMailCommandController.php @@ -52,9 +52,12 @@ class SendMailCommandController extends CommandController { * * @param int $sendCount * @return void + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException */ public function runSendMailsCommand($sendCount = 50) { $mailsToSend = $this->mailRepository->findMailsToSend($sendCount); + foreach ($mailsToSend as $mailToSend) { /** @var Mail $mailToSend */ $fromAddress = $mailToSend->getFromAddress(); @@ -64,7 +67,9 @@ class SendMailCommandController extends CommandController { $mailSubject = $mailToSend->getMailSubject(); $mailBody = $mailToSend->getMailBody(); - $mailToSend->setSent(TRUE); + $mailToSend->setSendingTime(time()); + $mailToSend->setLastSendingTime(time()); + $this->mailRepository->update($mailToSend); if (empty($fromAddress) || empty($toAddress) || empty($mailSubject)) { continue; diff --git a/Classes/Controller/MailController.php b/Classes/Controller/MailController.php index 735748ae9a76a84d429043acecb7332c9a0b00d2..092f838c6463337e226c0245dc4198efd7dad928 100644 --- a/Classes/Controller/MailController.php +++ b/Classes/Controller/MailController.php @@ -1,4 +1,5 @@ <?php + namespace SGalinski\SgMail\Controller; /*************************************************************** @@ -69,20 +70,16 @@ class MailController extends ActionController { /** * Show template Selection and enable content input + mail preview * - * @param string $selectedTemplate - * @param string $selectedExtension - * @param string $selectedLanguageLeft - * @param string $selectedLanguageRight + * @param array $parameters * @throws \InvalidArgumentException * @throws \UnexpectedValueException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException + * @throws \BadFunctionCallException + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException */ - public function indexAction( - $selectedTemplate = NULL, $selectedExtension = NULL, $selectedLanguageLeft = NULL, - $selectedLanguageRight = NULL - ) { - $siteRootId = BackendService::getSiteRoot((int) GeneralUtility::_GP('id')); + public function indexAction(array $parameters = []) { + $pid = (int) GeneralUtility::_GP('id'); if (!($this->session instanceof PhpSession)) { $this->session = $this->objectManager->get(PhpSession::class); @@ -96,89 +93,72 @@ class MailController extends ActionController { $this->redirect('empty'); } - $languages = BackendService::getLanguages(); - - $this->view->assign('languages', $languages); - $this->view->assign('templates', MailTemplateService::getRegisterArray()); - - // get language selection or read from cache or get default - $selectedLanguages = BackendService::getSelectedLanguages( - $selectedLanguageLeft, $selectedLanguageRight, $this->session, $languages - ); - - if ($selectedTemplate === NULL || $selectedTemplate === '') { - $selectedExtension = key($registerArray); - $selectedTemplate = key($registerArray[$selectedExtension]); + if ($parameters['selectedTemplate'] === NULL || $parameters['selectedTemplate'] === '') { + $parameters['selectedExtension'] = key($registerArray); + $parameters['selectedTemplate'] = key($registerArray[$parameters['selectedExtension']]); } - $selectedTemplates = BackendService::getSelectedTemplates( - $selectedExtension, $selectedTemplate, $selectedLanguages, $this->session, $siteRootId + $languages = BackendService::getLanguages(); + + $templatesFromDb = BackendService::getSelectedTemplates( + $parameters['selectedExtension'], $parameters['selectedTemplate'], $languages, + $pid ); - if ($selectedTemplates['left'] instanceof Template) { - $this->view->assign('contentLeft', $selectedTemplates['left']->getContent()); - $this->view->assign('fromNameLeft', $selectedTemplates['left']->getFromName()); - $this->view->assign('fromMailLeft', $selectedTemplates['left']->getFromMail()); - $this->view->assign('ccLeft', $selectedTemplates['left']->getCc()); - $this->view->assign('bccLeft', $selectedTemplates['left']->getBcc()); - $this->view->assign('replyToLeft', $selectedTemplates['left']->getReplyTo()); - } else { - $defaultTemplatePath = $registerArray[$selectedExtension][$selectedTemplate]['templatePath']; - $defaultTemplateFile = $defaultTemplatePath . $selectedLanguages['left'] . '.' . 'template.html'; - if (file_exists($defaultTemplateFile)) { - $this->view->assign('contentLeft', file_get_contents($defaultTemplateFile)); + // if no templates are in the db, get the default from the files + $templates = []; + $subject = $registerArray[$parameters['selectedExtension']][$parameters['selectedTemplate']]['subject']; + /** @var Template $template */ + foreach ($templatesFromDb as $key => $template) { + if ($template === NULL) { + $defaultTemplatePath = $registerArray[$parameters['selectedExtension']][$parameters['selectedTemplate']]['templatePath']; + $defaultTemplateFile = $defaultTemplatePath . $key . '.' . 'template.html'; + $fallbackTemplateFile = $defaultTemplatePath . 'template.html'; + + $templateFromFile = new Template(); + $templateFromFile->setLanguage($key); + $templates[$key] = $templateFromFile; + + if (file_exists($defaultTemplateFile)) { + $templateFromFile->setContent(file_get_contents($defaultTemplateFile)); + $templateFromFile->setSubject($subject); + } else { + // set subject from register array + $templateFromFile->setSubject(LocalizationUtility::translate($subject, $this->extensionName)); + + if (file_exists($fallbackTemplateFile)) { + $templateFromFile->setContent(file_get_contents($fallbackTemplateFile)); + } + } + } else { + $templates[$key] = $template; + $template->setIsOverwritten(TRUE); } } - if ($selectedTemplates['right'] instanceof Template) { - $this->view->assign('contentRight', $selectedTemplates['right']->getContent()); - $this->view->assign('fromNameRight', $selectedTemplates['right']->getFromName()); - $this->view->assign('fromMailRight', $selectedTemplates['right']->getFromMail()); - $this->view->assign('ccRight', $selectedTemplates['right']->getCc()); - $this->view->assign('bccRight', $selectedTemplates['right']->getBcc()); - $this->view->assign('replyToRight', $selectedTemplates['right']->getReplyTo()); - } else { - $defaultTemplatePath = $registerArray[$selectedExtension][$selectedTemplate]['templatePath']; - $defaultTemplateFile = $defaultTemplatePath . $selectedLanguages['right'] . '.' . 'template.html'; - if (file_exists($defaultTemplateFile)) { - $this->view->assign('contentRight', file_get_contents($defaultTemplateFile)); - } + // calculating optimal column width for the view + $colspace = 4; + $templateCount = count($templates); + if ($templateCount % 2 === 0 && $templateCount <= 4) { + $colspace = 6; + } elseif ($templateCount === 1) { + $colspace = 12; } - $subject = $registerArray[$selectedExtension][$selectedTemplate]['subject']; - - if (is_array($subject)) { - $this->view->assign( - 'subjectLeft', $selectedTemplates['left'] !== NULL ? $selectedTemplates['left']->getSubject() : - $registerArray[$selectedExtension][$selectedTemplate]['subject'][$selectedLanguages['left']] - ); - - $this->view->assign( - 'subjectRight', $selectedTemplates['right'] !== NULL ? $selectedTemplates['right']->getSubject() : - $registerArray[$selectedExtension][$selectedTemplate]['subject'][$selectedLanguages['right']] - ); - } else { - $translatedSubjects = BackendService::getTranslatedTemplateSubject( - $subject, $selectedExtension, $selectedLanguages - ); - - $this->view->assign( - 'subjectLeft', $selectedTemplates['left'] !== NULL ? $selectedTemplates['left']->getSubject() : - $translatedSubjects['left'] - ); + $this->view->assign('colspace', $colspace); + $this->view->assign('languageTemplates', $templates); + $this->view->assign('languageLabels', BackendService::getLanguageLabels($languages)); + $this->view->assign('templates', MailTemplateService::getRegisterArray()); - $this->view->assign( - 'subjectRight', $selectedTemplates['right'] !== NULL ? $selectedTemplates['right']->getSubject() : - $translatedSubjects['right'] - ); - } + $templateDescription = $registerArray[$parameters['selectedExtension']][$parameters['selectedTemplate']]['description']; - $templateDescription = $registerArray[$selectedExtension][$selectedTemplate]['description']; if (is_array($templateDescription)) { - $templateDescription = $templateDescription[$selectedLanguages['left']]; + if ($languages[0]['isocode']) { + $templateDescription = $templateDescription[$languages[0]['isocode']]; + } } else { $templateDescription = LocalizationUtility::translate( - $templateDescription, $selectedExtension + $templateDescription, $parameters['selectedExtension'] ); } @@ -186,167 +166,118 @@ class MailController extends ActionController { $pageUid = (int) GeneralUtility::_GP('id'); $pageInfo = BackendUtility::readPageAccess($pageUid, $GLOBALS['BE_USER']->getPagePermsClause(1)); - if ($pageInfo) { - $this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class); - $this->docHeaderComponent->setMetaInformation($pageInfo); - BackendService::makeButtons($this->docHeaderComponent, $this->request); + if ($pageInfo && $pageInfo['is_siteroot'] === '1') { - $this->view->assign('docHeader', $this->docHeaderComponent->docHeaderContent()); $this->view->assign('templateDescription', $templateDescription); - $this->view->assign('selectedTemplate', $registerArray[$selectedExtension][$selectedTemplate]); - $this->view->assign('selectedTemplateKey', $selectedTemplate); - $this->view->assign('selectedExtensionKey', $selectedExtension); - $this->view->assign('selectedLanguageLeft', $selectedLanguages['left']); - $this->view->assign('selectedLanguageRight', $selectedLanguages['right']); + $this->view->assign( + 'selectedTemplate', $registerArray[$parameters['selectedExtension']][$parameters['selectedTemplate']] + ); + $this->view->assign('selectedTemplateKey', $parameters['selectedTemplate']); + $this->view->assign('selectedExtensionKey', $parameters['selectedExtension']); $this->view->assign('mode', 'editor'); + } else { + $this->view->assign('pages', BackendService::getPages()); } - $this->view->assign('typo3Version', VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version)); - } + $this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class); + $this->docHeaderComponent->setMetaInformation($pageInfo); + BackendService::makeButtons($this->docHeaderComponent, $this->request); - /** - * Save content (left & right) - * if left & right is the same language, the right content will apply only if its another language - * - * @param string $contentLeft - * @param string $contentRight - * @param string $selectedExtension - * @param string $selectedTemplate - * @param string $selectedLanguageLeft - * @param string $selectedLanguageRight - * @param string $subjectLeft - * @param string $subjectRight - * @param string $fromNameLeft - * @param string $fromMailLeft - * @param string $ccLeft - * @param string $bccLeft - * @param string $replyToLeft - * @param string $fromNameRight - * @param string $fromMailRight - * @param string $ccRight - * @param string $bccRight - * @param string $replyToRight - * @throws \InvalidArgumentException - * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException - * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException - * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException - * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException - */ - public function saveAction( - $contentLeft = NULL, $contentRight = NULL, $selectedExtension = NULL, $selectedTemplate = NULL, - $selectedLanguageLeft = NULL, $selectedLanguageRight = NULL, $subjectLeft = NULL, $subjectRight = NULL, - $fromNameLeft = NULL, $fromMailLeft = NULL, $ccLeft = NULL, $bccLeft = NULL, $replyToLeft = NULL, - $fromNameRight = NULL, $fromMailRight = NULL, $ccRight = NULL, $bccRight = NULL, $replyToRight = NULL - ) { - $this->saveTemplate( - $selectedExtension, $selectedTemplate, $selectedLanguageLeft, $contentLeft, $subjectLeft, - $fromNameLeft, $fromMailLeft, $ccLeft, $bccLeft, $replyToLeft - ); - if ($selectedLanguageLeft !== $selectedLanguageRight) { - $this->saveTemplate( - $selectedExtension, $selectedTemplate, $selectedLanguageRight, $contentRight, $subjectRight, - $fromNameRight, $fromMailRight, $ccRight, $bccRight, $replyToRight + $this->view->assign('docHeader', $this->docHeaderComponent->docHeaderContent()); + $this->view->assign('typo3Version', VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version)); + $this->view->assign('beUserMail', $GLOBALS['BE_USER']->user['email']); + + // get the default language label and pass it to the view + $languageService = $GLOBALS['LANG']; + $pageTsConfig = BackendUtility::getPagesTSconfig($pageUid); + if (VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) >= 8000000) { + $defaultLanguageLabel = $languageService->sL( + 'LLL:EXT:lang/Resources/Private/Language/locallang_mod_web_list.xlf:defaultLanguage' + ); + } else { + $defaultLanguageLabel = $languageService->sL( + 'lll:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage' ); } - $message = LocalizationUtility::translate('backend.success', 'sg_mail'); - $this->addFlashMessage($message, '', FlashMessage::OK); - $arguments = $this->request->getArguments(); - $this->redirect('index', NULL, NULL, $arguments); + if (isset($pageTsConfig['mod.']['SHARED.']['defaultLanguageLabel'])) { + $defaultLanguageLabel = $pageTsConfig['mod.']['SHARED.']['defaultLanguageLabel']; + } + + $this->view->assign('defaultLanguageLabel', $defaultLanguageLabel); } /** - * Save or update the template in the DB, depending if it already exists or not + * send a test email to a given address + * redirect to index action * - * @param string $selectedExtension - * @param string $selectedTemplate - * @param string $selectedLanguage - * @param string $selectedContent - * @param string $selectedSubject - * @param string $selectedFromName - * @param string $selectedFromMail - * @param string $selectedCc - * @param string $selectedBcc - * @param string $selectedReplyTo - * @return Template $template + * @param array $parameters * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException + * @throws \BadFunctionCallException + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException */ - private function saveTemplate( - $selectedExtension, $selectedTemplate, $selectedLanguage, $selectedContent, $selectedSubject, - $selectedFromName, $selectedFromMail, $selectedCc, $selectedBcc, $selectedReplyTo - ) { - $siteRootId = BackendService::getSiteRoot((int) GeneralUtility::_GP('id')); - - /** @var Template $template */ - $template = $this->templateRepository->findOneByTemplate( - $selectedExtension, $selectedTemplate, $selectedLanguage, $siteRootId - ); + public function sendTestMailAction(array $parameters = []) { + foreach ((array) $parameters['templates'] as $parameter) { + $ccAddresses = GeneralUtility::trimExplode(',', $parameter['cc']); + if (count($ccAddresses) > 0) { + + foreach ($ccAddresses as $ccAddress) { + if (!filter_var($ccAddress, FILTER_VALIDATE_EMAIL) && trim($ccAddress) !== '') { + $message = LocalizationUtility::translate('backend.error_cc', 'sg_mail'); + $this->addFlashMessage($message, '', FlashMessage::WARNING); + + $arguments = $this->request->getArguments(); + $this->redirect('index', NULL, NULL, $arguments); + } + } + } - $templateAlreadyExists = TRUE; - $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - if ($template === NULL) { - $templateAlreadyExists = FALSE; - $template = $objectManager->get(Template::class); + $bccAddresses = GeneralUtility::trimExplode(',', $parameter['bcc']); + if (count($bccAddresses) > 0) { + foreach ($bccAddresses as $bccAddress) { + if (!filter_var($bccAddress, FILTER_VALIDATE_EMAIL) && trim($bccAddress) !== '') { + $message = LocalizationUtility::translate('backend.error_bcc', 'sg_mail'); + $this->addFlashMessage($message, '', FlashMessage::WARNING); + + $arguments = $this->request->getArguments(); + $this->redirect('index', NULL, NULL, $arguments); + } + } + } } - $template->setExtensionKey($selectedExtension); - $template->setTemplateName($selectedTemplate); - $template->setLanguage($selectedLanguage); - $template->setContent($selectedContent); - $template->setSubject($selectedSubject); - $template->setFromName($selectedFromName); - $template->setFromMail($selectedFromMail); - $template->setCc($selectedCc); - $template->setBcc($selectedBcc); - $template->setReplyTo($selectedReplyTo); - $template->setSiteRootId($siteRootId); - - if ($templateAlreadyExists) { - $this->templateRepository->update($template); - } else { - $this->templateRepository->add($template); + foreach ((array) $parameters['templates'] as $key => $template) { + BackendService::saveTemplate( + (int) GeneralUtility::_GP('id'), $parameters['selectedExtension'], $parameters['selectedTemplate'], + $key, $template + ); } - return $template; - } + $message = LocalizationUtility::translate('backend.success', 'sg_mail'); + $this->addFlashMessage($message, '', FlashMessage::OK); + + if (!filter_var($parameters['emailAddress'], FILTER_VALIDATE_EMAIL)) { + $arguments = $this->request->getArguments(); + $this->redirect('index', NULL, NULL, $arguments); + } - /** - * send a test email to a given address - * redirect to index action - * - * @param string $emailAddress - * @param string $selectedTemplateKey - * @param string $selectedExtensionKey - * @param string $selectedLanguageLeft - * @param string $selectedLanguageRight - * @throws \InvalidArgumentException - * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException - * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException - * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException - */ - public function sendTestMailAction( - $emailAddress, $selectedExtensionKey, $selectedTemplateKey, $selectedLanguageLeft, $selectedLanguageRight - ) { $objectManager = GeneralUtility::makeInstance(ObjectManager::class); /** @var \SGalinski\SgMail\Service\MailTemplateService $mailTemplateService */ - $mailTemplateService = $objectManager->get(MailTemplateService::class); - $mailTemplateService->setLanguage($selectedLanguageLeft); - $mailTemplateService->setToAddresses($emailAddress); - $mailTemplateService->setFromAddress('noreply@example.org'); - $mailTemplateService->setTemplateName($selectedTemplateKey); - $mailTemplateService->setExtensionKey($selectedExtensionKey); - $mailIsSend = $mailTemplateService->sendEmail(TRUE); - - if ($selectedLanguageRight !== $selectedLanguageLeft) { - /** @var \SGalinski\SgMail\Service\MailTemplateService $mailTemplateService */ - $mailTemplateService = $objectManager->get(MailTemplateService::class); - $mailTemplateService->setLanguage($selectedLanguageRight); - $mailTemplateService->setToAddresses($emailAddress); - $mailTemplateService->setFromAddress('noreply@example.org'); - $mailTemplateService->setTemplateName($selectedTemplateKey); - $mailTemplateService->setExtensionKey($selectedExtensionKey); + $mailTemplateService = $objectManager->get( + MailTemplateService::class, $parameters['selectedTemplate'], $parameters['selectedExtension'] + ); + $mailIsSend = FALSE; + + foreach ((array) $parameters['templates'] as $key => $template) { + $mailTemplateService->setLanguage($key); + $mailTemplateService->setToAddresses($parameters['emailAddress']); + $mailTemplateService->setFromAddress($template['fromMail']); + $mailTemplateService->setTemplateName($parameters['selectedTemplate']); + $mailTemplateService->setExtensionKey($parameters['selectedExtension']); $mailIsSend = $mailTemplateService->sendEmail(TRUE); } @@ -374,13 +305,12 @@ class MailController extends ActionController { * * @param string $template * @param string $extensionKey - * @param string $language * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException */ - public function resetAction($template, $extensionKey, $language = '') { - $this->templateRepository->deleteTemplate($extensionKey, $template, $language); + public function resetAction($template, $extensionKey) { + $this->templateRepository->deleteTemplate($extensionKey, $template); $message = LocalizationUtility::translate('backend.template_reset', 'sg_mail'); $this->addFlashMessage($message, '', FlashMessage::OK); diff --git a/Classes/Controller/QueueController.php b/Classes/Controller/QueueController.php index 2b7c0b468424f501375513fa3ca443f40130cc25..2254619e9a5153584035b6ecafe55c1f64bacca7 100644 --- a/Classes/Controller/QueueController.php +++ b/Classes/Controller/QueueController.php @@ -1,4 +1,5 @@ <?php + namespace SGalinski\SgMail\Controller; /*************************************************************** @@ -60,51 +61,102 @@ class QueueController extends ActionController { /** * @param string $selectedTemplate * @param string $selectedExtension + * @param array $filters * @throws \InvalidArgumentException * @throws \UnexpectedValueException + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException + * @throws \BadFunctionCallException + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException */ - public function indexAction($selectedTemplate = NULL, $selectedExtension = NULL) { - $registerArray = MailTemplateService::getRegisterArray(); + public function indexAction($selectedTemplate = NULL, $selectedExtension = NULL, array $filters = []) { + $filterTemplate = $_POST['filterTemplate']; + $filters['filterExtension'] = $filterTemplate; + $filters['filterTemplate'] = $filterTemplate; + + if ($_POST['filterTemplate'] !== '') { + $extensionTemplateFilterArray = explode('###', $filterTemplate); + $filters['filterExtension'] = $extensionTemplateFilterArray[0]; + $filters['filterTemplate'] = $extensionTemplateFilterArray[1]; + } + $this->view->assign('selectedTemplateFilter', $filters['filterTemplate']); + $this->view->assign('selectedExtensionFilter', $filters['filterExtension']); + + $registerArray = MailTemplateService::getRegisterArray(); if ($selectedTemplate === NULL || $selectedTemplate === '') { $selectedExtension = key($registerArray); $selectedTemplate = key($registerArray[$selectedExtension]); } - $siteRootId = BackendService::getSiteRoot((int) GeneralUtility::_GP('id')); - $queue = $this->mailRepository->findAllEntries($selectedExtension, $selectedTemplate, $siteRootId); + $pageUid = (int) GeneralUtility::_GP('id'); + $queue = $this->mailRepository->findAllEntries($pageUid, 0, $filters); // create doc header component - $pageUid = (int) GeneralUtility::_GP('id'); $pageInfo = BackendUtility::readPageAccess($pageUid, $GLOBALS['BE_USER']->getPagePermsClause(1)); - - if ($pageInfo) { - $this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class); - - $this->docHeaderComponent->setMetaInformation($pageInfo); - $this->view->assign('docHeader', $this->docHeaderComponent->docHeaderContent()); - BackendService::makeButtons($this->docHeaderComponent, $this->request); - + if ($pageInfo && $pageInfo['is_siteroot'] === '1') { $this->view->assign('selectedTemplateKey', $selectedTemplate); $this->view->assign('selectedExtensionKey', $selectedExtension); $this->view->assign('templates', $registerArray); - $this->view->assign('queue', $queue); + + $this->view->assign('templatesFilter', BackendService::getTemplatesForFilter()); + $this->view->assign('languages', BackendService::getLanguagesForFilter()); + $this->view->assign('mode', 'queue'); + if (!$filters['filterSent']) { + $filters['filterSent'] = 0; + } + $this->view->assign('filters', $filters); + $this->view->assign('queue', $queue); + $this->view->assign( + 'filterFields', [ + BackendService::SENDER_FILTER_OPTION => LocalizationUtility::translate( + 'backend.filter.from', 'SgMail' + ), + BackendService::RECIPIENT_FILTER_OPTION => LocalizationUtility::translate( + 'backend.filter.to', 'SgMail' + ), + BackendService::SUBJECT_FILTER_OPTION => LocalizationUtility::translate( + 'backend.filter.subject', 'SgMail' + ), + BackendService::MAILTEXT_FILTER_OPTION => LocalizationUtility::translate( + 'backend.filter.mailtext', 'SgMail' + ), + BackendService::CC_FILTER_OPTION => LocalizationUtility::translate('backend.filter.cc', 'SgMail'), + BackendService::BCC_FILTER_OPTION => LocalizationUtility::translate('backend.filter.bcc', 'SgMail'), + BackendService::FROM_NAME_FILTER_OPTION => LocalizationUtility::translate( + 'backend.filter.from_name', 'SgMail' + ), + BackendService::REPLY_TO_NAME_FILTER_OPTION => LocalizationUtility::translate( + 'backend.filter.reply_to', 'SgMail' + ), + ] + ); + } else { + $this->view->assign('pages', BackendService::getPages()); } + $this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class); + + $this->docHeaderComponent->setMetaInformation($pageInfo); + $this->view->assign('docHeader', $this->docHeaderComponent->docHeaderContent()); + BackendService::makeButtons($this->docHeaderComponent, $this->request); $this->view->assign('typo3Version', VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version)); + } /** * send or resend a mail in the queue * * @param int $uid + * @param string $selectedTemplate + * @param string $selectedExtension * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException */ - public function sendMailAction($uid) { + public function sendMailAction($uid, $selectedTemplate, $selectedExtension) { + $mailService = new MailTemplateService(); $mailService->sendMailFromQueue($uid); @@ -113,4 +165,24 @@ class QueueController extends ActionController { $arguments = $this->request->getArguments(); $this->redirect('index', NULL, NULL, $arguments); } + + /** + * Download the queue data as a csv file, respecting the filter settings + * + * @param array $filters + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException + * @throws \InvalidArgumentException + */ + public function exportAction(array $filters = []) { + $exportString = BackendService::getCsvFromQueue($filters); + + header('Content-Type: application/force-download'); + header('Content-Transfer-Encoding: Binary'); + header('Content-Disposition: attachment; filename="export.csv"'); + header('Content-Length: ' . strlen($exportString)); + echo $exportString; + exit(0); + } } diff --git a/Classes/Domain/Model/Mail.php b/Classes/Domain/Model/Mail.php index 9db628c5d703ccd7863da3cacb7f2dad318b4b27..b3e346c9b12e1b6195c6218e3eea06acdb16bcac 100644 --- a/Classes/Domain/Model/Mail.php +++ b/Classes/Domain/Model/Mail.php @@ -40,9 +40,9 @@ class Mail extends AbstractEntity { const PRIORITY_HIGHEST = 200; /** - * @var int + * @var string */ - protected $siteRootId = 0; + protected $language = ''; /** * @var string @@ -64,11 +64,6 @@ class Mail extends AbstractEntity { */ protected $fromAddress = ''; - /** - * @var bool - */ - protected $sent = FALSE; - /** * @var int */ @@ -109,6 +104,11 @@ class Mail extends AbstractEntity { */ protected $sendingTime = 0; + /** + * @var int + */ + protected $lastSendingTime = 0; + /** * @return string */ @@ -169,21 +169,6 @@ class Mail extends AbstractEntity { $this->fromAddress = $fromAddress; } - /** - * @return bool - */ - public function getSent() { - return $this->sent; - } - - /** - * @param bool $sent - * @return void - */ - public function setSent($sent) { - $this->sent = ($sent === TRUE); - } - /** * @return int */ @@ -294,20 +279,34 @@ class Mail extends AbstractEntity { * @param int $sendingTime */ public function setSendingTime($sendingTime) { - $this->sendingTime = $sendingTime; + $this->sendingTime = (int) $sendingTime; } /** * @return int */ - public function getSiteRootId() { - return $this->siteRootId; + public function getLastSendingTime() { + return $this->lastSendingTime; + } + + /** + * @param int $sendingTime + */ + public function setLastSendingTime($sendingTime) { + $this->lastSendingTime = (int) $sendingTime; + } + + /** + * @return string + */ + public function getLanguage() { + return $this->language; } /** - * @param int $siteRootId + * @param string $language */ - public function setSiteRootId($siteRootId) { - $this->siteRootId = (int) $siteRootId; + public function setLanguage($language) { + $this->language = $language; } } diff --git a/Classes/Domain/Model/Template.php b/Classes/Domain/Model/Template.php index 150033895a51a004ed060b85d4ce178d8fa0d2d2..993cc472f44e099fd9a815dbf6bb91c440d2d90b 100644 --- a/Classes/Domain/Model/Template.php +++ b/Classes/Domain/Model/Template.php @@ -32,11 +32,6 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; * Template domain model */ class Template extends AbstractEntity { - /** - * @var int - */ - protected $siteRootId = 0; - /** * @var string */ @@ -87,6 +82,16 @@ class Template extends AbstractEntity { */ protected $replyTo = ''; + /** + * @var string + */ + protected $toAddress = ''; + + /** + * @var boolean + */ + protected $isOverwritten = FALSE; + /** * @return string */ @@ -228,16 +233,30 @@ class Template extends AbstractEntity { } /** - * @return int + * @return bool + */ + public function getIsOverwritten() { + return $this->isOverwritten; + } + + /** + * @param bool $isOverwritten + */ + public function setIsOverwritten($isOverwritten) { + $this->isOverwritten = (bool) $isOverwritten; + } + + /** + * @return string */ - public function getSiteRootId() { - return $this->siteRootId; + public function getToAddress() { + return $this->toAddress; } /** - * @param int $siteRootId + * @param string $toAddress */ - public function setSiteRootId($siteRootId) { - $this->siteRootId = (int) $siteRootId; + public function setToAddress($toAddress) { + $this->toAddress = $toAddress; } } diff --git a/Classes/Domain/Repository/MailRepository.php b/Classes/Domain/Repository/MailRepository.php index a611a204da83ee3c7ad405fb5514b7afc07ab2aa..e7c87b6187a5dbf4e128b115581cc4689e38568d 100644 --- a/Classes/Domain/Repository/MailRepository.php +++ b/Classes/Domain/Repository/MailRepository.php @@ -26,6 +26,7 @@ namespace SGalinski\SgMail\Domain\Repository; * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use SGalinski\SgMail\Service\BackendService; use TYPO3\CMS\Extbase\Persistence\Generic\Query; use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; @@ -33,6 +34,9 @@ use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; * Repository for the Mail object */ class MailRepository extends AbstractRepository { + const SENT = '1'; + const NOT_SENT = '2'; + /** * Returns all mails that are still not sent ordered by priority. * @@ -53,21 +57,109 @@ class MailRepository extends AbstractRepository { /** * Find all mails (sent & unsent) for extension key and template name * - * @param string $extensionKey - * @param string $templateName - * @param int $siteroot + * @param int $pid * @param int $limit + * @param array $filters * @return array|QueryResultInterface + * @throws \InvalidArgumentException + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException */ - public function findAllEntries($extensionKey, $templateName, $siteroot = 0, $limit = NULL) { + public function findAllEntries($pid = 0, $limit = NULL, array $filters = []) { $query = $this->createQuery(); if ($limit) { $query->setLimit($limit); } - $constraintsAnd[] = $query->equals('extension_key', $extensionKey); - $constraintsAnd[] = $query->equals('template_name', $templateName); - $constraintsAnd[] = $query->equals('site_root_id', (int) $siteroot); + if ($filters['filterExtension'] && $filters['filterExtension'] !== 0 + && $filters['filterExtension'] !== '0' && $filters['filterExtension'] !== '' + ) { + $constraintsAnd[] = $query->equals('extension_key', $filters['filterExtension']); + } + + if ($filters['filterTemplate'] && $filters['filterTemplate'] !== 0 + && $filters['filterTemplate'] !== '0' && $filters['filterTemplate'] !== '' + ) { + $constraintsAnd[] = $query->equals('template_name', $filters['filterTemplate']); + } + + // if this language is no in the sys lang table, then include it with the default lang + if ($filters['filterLanguage'] === 'default') { + foreach (BackendService::getLanguages() as $lang) { + $constraintsAnd[] = $query->logicalNot($query->equals('language', $lang['isocode'])); + } + } else { + if ($filters['filterLanguage'] && $filters['filterLanguage'] !== 0 + && $filters['filterLanguage'] !== '0' && $filters['filterLanguage'] !== '' + ) { + $constraintsAnd[] = $query->equals('language', $filters['filterLanguage']); + } + } + + $constraintsOr = []; + $search = '%' . $filters['filterSearch'] . '%'; + if ($filters['filterFields'] && trim('' !== $filters['filterFields'])) { + foreach ($filters['filterFields'] as $field) { + switch ($field) { + case BackendService::SENDER_FILTER_OPTION : + $constraintsOr[] = $query->like('from_address', $search); + break; + case BackendService::RECIPIENT_FILTER_OPTION : + $constraintsOr[] = $query->like('to_address', $search); + break; + case BackendService::SUBJECT_FILTER_OPTION : + $constraintsOr[] = $query->like('mail_subject', $search); + break; + case BackendService::MAILTEXT_FILTER_OPTION : + $constraintsOr[] = $query->like('mail_body', $search); + break; + case BackendService::CC_FILTER_OPTION : + $constraintsOr[] = $query->like('cc_addresses', $search); + break; + case BackendService::BCC_FILTER_OPTION : + $constraintsOr[] = $query->like('bcc_addresses', $search); + break; + case BackendService::FROM_NAME_FILTER_OPTION : + $constraintsOr[] = $query->like('from_name', $search); + break; + case BackendService::REPLY_TO_NAME_FILTER_OPTION : + $constraintsOr[] = $query->like('reply_to', $search); + break; + } + } + } else { // if nothing selected, search in all fields + $constraintsOr[] = $query->like('from_address', $search); + $constraintsOr[] = $query->like('to_address', $search); + $constraintsOr[] = $query->like('mail_subject', $search); + $constraintsOr[] = $query->like('mail_body', $search); + $constraintsOr[] = $query->like('cc_addresses', $search); + $constraintsOr[] = $query->like('bcc_addresses', $search); + $constraintsOr[] = $query->like('from_name', $search); + $constraintsOr[] = $query->like('reply_to', $search); + } + $constraintsAnd[] = $query->logicalOr($constraintsOr); + + $fromTime = strtotime($filters['filterFromDate']); + if ($fromTime) { + $constraintsAnd[] = $query->greaterThanOrEqual('last_sending_time', $fromTime); + } + + $toTime = strtotime($filters['filterToDate']); + if ($toTime) { + $constraintsAnd[] = $query->lessThanOrEqual('last_sending_time', $toTime); + } + + if ($filters['filterSent']) { + switch ($filters['filterSent']) { + case self::SENT: + $constraintsAnd[] = $query->greaterThan('last_sending_time', 0); + break; + case self::NOT_SENT: + $constraintsAnd[] = $query->equals('last_sending_time', 0); + break; + } + } + + $constraintsAnd[] = $query->equals('pid', (int) $pid); $query->setOrderings(['tstamp' => Query::ORDER_DESCENDING]); return $query->matching($query->logicalAnd($constraintsAnd))->execute(TRUE); diff --git a/Classes/Domain/Repository/TemplateRepository.php b/Classes/Domain/Repository/TemplateRepository.php index d8663f06a7b8d735b43b9ea200b03562d46669b9..f93b06252102416dc23e6e412936dff434215d13 100644 --- a/Classes/Domain/Repository/TemplateRepository.php +++ b/Classes/Domain/Repository/TemplateRepository.php @@ -38,11 +38,11 @@ class TemplateRepository extends AbstractRepository { * @param string $extensionKey * @param string $templateName * @param string $language - * @param int $siteRoot + * @param int $pid * * @return Template */ - public function findOneByTemplate($extensionKey, $templateName, $language, $siteRoot = 0) { + public function findOneByTemplate($extensionKey, $templateName, $language, $pid = 0) { $query = $this->createQuery(); $querySettings = $this->objectManager->get(Typo3QuerySettings::class); @@ -51,7 +51,7 @@ class TemplateRepository extends AbstractRepository { $constraintsAnd[] = $query->equals('extension_key', $extensionKey); $constraintsAnd[] = $query->equals('template_name', $templateName); $constraintsAnd[] = $query->equals('language', $language); - $constraintsAnd[] = $query->equals('site_root_id', (int) $siteRoot); + $constraintsAnd[] = $query->equals('pid', (int) $pid); $query->matching( $query->logicalAnd($constraintsAnd) @@ -67,18 +67,15 @@ class TemplateRepository extends AbstractRepository { * * @param $extensionKey * @param $templateName - * @param $language */ - public function deleteTemplate($extensionKey, $templateName, $language) { + public function deleteTemplate($extensionKey, $templateName) { /** @var $databaseConnection DatabaseConnection */ $databaseConnection = $GLOBALS['TYPO3_DB']; $tableName = 'tx_sgmail_domain_model_template'; $where = 'extension_key = ' . $databaseConnection->fullQuoteStr($extensionKey, $tableName); $where.= ' AND template_name = ' . $databaseConnection->fullQuoteStr($templateName, $tableName); - if ($language !== '') { - $where.= ' AND language = ' . $databaseConnection->fullQuoteStr($language, $tableName); - } + $databaseConnection->exec_DELETEquery($tableName, $where); } } diff --git a/Classes/Example/Register.php b/Classes/Example/Register.php deleted file mode 100644 index 2040d1c69a969bd6d28a921a99c3240b921d08c3..0000000000000000000000000000000000000000 --- a/Classes/Example/Register.php +++ /dev/null @@ -1,222 +0,0 @@ -<?php - -namespace SGalinski\SgMail\Example; - -/*************************************************************** - * Copyright notice - * - * (c) sgalinski Internet Services (https://www.sgalinski.de) - * - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - ***************************************************************/ - -use SGalinski\SgMail\Service\RegisterInterface; - -/** - * Example Registration for a Template - * - * @package SGalinski\SgMail\Example - */ -class Register implements RegisterInterface { - - /** - * @var array - */ - private $markers = []; - - /** - * @var array - */ - private $subject = []; - - /** - * @var string - */ - private $description; - - /** - * the extension key - * - * @var string - */ - private $extensionKey; - - /** - * a unique name for this template - * - * @var string - */ - private $templateKey; - - /** - * path where the template is located - * - * @var string - */ - private $templatePath; - - /** - * initialize certain values - */ - public function init() { - $templateArray = [ - 'firstName' => 'Max', - 'lastName' => 'Mustermann' - ]; - - $this->markers = [ - [ - 'marker' => 'firstname', - 'type' => \SGalinski\SgMail\Service\MailTemplateService::MARKER_TYPE_STRING, - 'value' => 'Max', - 'description' => 'The first name of the customer' - ], - [ - 'marker' => 'lastname', - 'type' => \SGalinski\SgMail\Service\MailTemplateService::MARKER_TYPE_STRING, - 'value' => 'Mustermann', - 'description' => 'The last name of the customer' - ], - [ - 'marker' => 'person', - 'type' => \SGalinski\SgMail\Service\MailTemplateService::MARKER_TYPE_ARRAY, - 'value' => $templateArray, - 'description' => 'An array with the customer data', - 'usage' => '{person.firstName}, {person.lastName}' - ] - ]; - - $this->description = 'Description about the Template'; - $this->subject = [ - 'en' => 'The english subject text', - 'de' => 'The german subject text' - ]; - - $this->templateKey = 'notice_mail_admin'; - $this->extensionKey = 'sg_sample'; - } - - /** - * Calls MailTemplateService registerTemplate with according values. - */ - public function registerTemplate() { - \SGalinski\SgMail\Service\MailTemplateService::registerTemplate( - $this->extensionKey, $this->templateKey, $this->templatePath, $this->description, $this->markers, - $this->subject - ); - } - - /** - * @return array - */ - public function getMarkers() { - return $this->markers; - } - - /** - * @param array $markers - * @return RegisterInterface - */ - public function setMarkers(array $markers) { - $this->markers = $markers; - return $this; - } - - /** - * @return array - */ - public function getSubject() { - return $this->subject; - } - - /** - * @param array $subject - * @return RegisterInterface - */ - public function setSubject(array $subject) { - $this->subject = $subject; - return $this; - } - - /** - * @return string - */ - public function getDescription() { - return $this->description; - } - - /** - * @param string $description - * @return RegisterInterface - */ - public function setDescription($description) { - $this->description = $description; - return $this; - } - - /** - * @return string - */ - public function getExtensionKey() { - return $this->extensionKey; - } - - /** - * @param string $extensionKey - * @return RegisterInterface - */ - public function setExtensionKey($extensionKey) { - $this->extensionKey = $extensionKey; - return $this; - } - - /** - * @return string - */ - public function getTemplateKey() { - return $this->templateKey; - } - - /** - * @param string $templateKey - * @return RegisterInterface - */ - public function setTemplateKey($templateKey) { - $this->templateKey = $templateKey; - return $this; - } - - /** - * @return string - */ - public function getTemplatePath() { - return $this->templatePath; - } - - /** - * @param string $templatePath - * @return RegisterInterface - */ - public function setTemplatePath($templatePath) { - $this->templatePath = $templatePath; - return $this; - } -} - -?> \ No newline at end of file diff --git a/Classes/Service/BackendService.php b/Classes/Service/BackendService.php index e57b32502bfa0bef85a3312776c4a5c4cc6af7d7..1e2eb853f905d3bbc727ef8ac5556f18391f25bd 100644 --- a/Classes/Service/BackendService.php +++ b/Classes/Service/BackendService.php @@ -26,6 +26,8 @@ namespace SGalinski\SgMail\Service; * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use SGalinski\SgMail\Domain\Model\Template; +use SGalinski\SgMail\Domain\Repository\MailRepository; use SGalinski\SgMail\Domain\Repository\TemplateRepository; use TYPO3\CMS\Backend\Template\Components\ButtonBar; use TYPO3\CMS\Backend\Template\Components\DocHeaderComponent; @@ -34,15 +36,26 @@ use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository; use TYPO3\CMS\Extbase\Mvc\Request; use TYPO3\CMS\Extbase\Object\ObjectManager; +use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; +use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; -use TYPO3\CMS\Lang\Domain\Repository\LanguageRepository; /** * Backend Service class */ class BackendService { + // options for the queue search filter + const SENDER_FILTER_OPTION = 0; + const RECIPIENT_FILTER_OPTION = 1; + const SUBJECT_FILTER_OPTION = 2; + const MAILTEXT_FILTER_OPTION = 3; + const CC_FILTER_OPTION = 4; + const BCC_FILTER_OPTION = 5; + const FROM_NAME_FILTER_OPTION = 6; + const REPLY_TO_NAME_FILTER_OPTION = 7; /** * Get all pages the be user has access to @@ -51,6 +64,7 @@ class BackendService { * @throws \InvalidArgumentException */ public static function getPages() { + $out = []; /** @var $databaseConnection DatabaseConnection */ $databaseConnection = $GLOBALS['TYPO3_DB']; $rows = $databaseConnection->exec_SELECTgetRows( @@ -59,7 +73,13 @@ class BackendService { 'deleted = 0 AND is_siteroot = 1' ); - return $rows; + foreach ($rows as $row) { + $pageInfo = BackendUtility::readPageAccess($row['uid'], $GLOBALS['BE_USER']->getPagePermsClause(1)); + if ($pageInfo) { + $out[] = $pageInfo; + } + } + return $out; } /** @@ -119,6 +139,34 @@ class BackendService { return $siteRoot['uid']; } + /** + * Get the selected templates for the selected language + * + * @param string $selectedExtension + * @param string $selectedTemplate + * @param array $languages + * @param int $pid + * @return array + * @throws \InvalidArgumentException + */ + public static function getSelectedTemplates( + $selectedExtension, $selectedTemplate, array $languages, $pid + ) { + $selectedTemplates = []; + + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + /** @var TemplateRepository $templateRepository */ + $templateRepository = $objectManager->get(TemplateRepository::class); + + foreach ($languages as $language) { + $selectedTemplates[$language['isocode']] = $templateRepository->findOneByTemplate( + $selectedExtension, $selectedTemplate, $language['isocode'], $pid + ); + } + + return $selectedTemplates; + } + /** * get an array of all the locales for the activated languages * @@ -126,123 +174,205 @@ class BackendService { * @throws \InvalidArgumentException */ public static function getLanguages() { - $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - /** @var LanguageRepository $languageRepository */ - $languageRepository = $objectManager->get(LanguageRepository::class); - $activatedLanguages = $languageRepository->findSelected(); + /** @var $databaseConnection DatabaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + /** @var QueryResultInterface $rows */ + $rows = $databaseConnection->exec_SELECTgetRows( + '*', + 'sys_language', + 'hidden = 0' + ); + + $languages = []; + + // adding default language + $languages[] = ['isocode' => MailTemplateService::DEFAULT_LANGUAGE, 'name' => LocalizationUtility::translate( + 'backend.language_default', 'SgMail' + )]; - $languages = ['en']; - foreach ($activatedLanguages as $language) { - $languages[] = $language->getLocale(); + foreach ($rows as $language) { + $languages[] = ['isocode' => $language['language_isocode'], + 'name' => $language['title']]; } return $languages; } /** - * Get the previous selected languages, the actual selection or the default - * format ['left' => languagecode, 'right' => ...] + * get an array of all the labels for the activated languages * - * @param string $selectedLanguageLeft - * @param string $selectedLanguageRight - * @param \SGalinski\SgMail\Session\PhpSession $session * @param array $languages * @return array + * @throws \InvalidArgumentException */ - public static function getSelectedLanguages( - $selectedLanguageLeft, $selectedLanguageRight, $session, array $languages - ) { - $selectedLanguages = [ - 'left' => $selectedLanguageLeft, - 'right' => $selectedLanguageRight - ]; - - if ($selectedLanguageLeft === NULL) { - $selectedLanguageLeftFromSession = $session->getDataByKey('selectedLanguageLeft'); - if ($selectedLanguageLeftFromSession !== NULL) { - $selectedLanguages['left'] = $selectedLanguageLeftFromSession; - } else { - $selectedLanguages['left'] = $languages[0]; + public static function getLanguageLabels(array $languages) { + $languageLabels = []; + + foreach ($languages as $language) { + $languageLabels[$language['isocode']] = $language['name']; + } + + return $languageLabels; + } + + /** + * Get the languages in an array suitable for filtering + * + * @return array + * @throws \InvalidArgumentException + */ + public static function getLanguagesForFilter() { + $languages = self::getLanguages(); + array_unshift($languages, ['isocode' => '', 'name' => '']); + + $filterLanguages = []; + if (count($languages) > 0) { + foreach ($languages as $language) { + $filterLanguages[$language['isocode']] = $language['name']; } } - if ($selectedLanguageRight === NULL) { - $selectedLanguageRightFromSession = $session->getDataByKey('selectedLanguageRight'); - if ($selectedLanguageRightFromSession === NULL) { - if (isset($languages[1])) { - $selectedLanguages['right'] = $languages[1]; - } else { - $selectedLanguages['right'] = $languages[0]; - } - } else { - $selectedLanguages['right'] = $selectedLanguageRightFromSession; + return $filterLanguages; + } + + /** + * Get the template keys in an array suitable for filtering + * + * @return array + */ + public static function getTemplatesForFilter() { + $registerArray = MailTemplateService::getRegisterArray(); + $templates = []; + foreach ($registerArray as $extensions) { + foreach ($extensions as $template => $key) { + $templates[$key['extension']][] = $key['templateName']; } } - return $selectedLanguages; + array_unshift($templates, ''); + + return $templates; } /** - * Get the selected templates for the selected language + * Save or update the template in the DB, depending if it already exists or not * + * @param int $pid * @param string $selectedExtension * @param string $selectedTemplate - * @param array $selectedLanguages - * @param \SGalinski\SgMail\Session\PhpSession $session - * @param int $siteRootId - * @return array + * @param string $language + * @param array $templateData + * @return Template $template * @throws \InvalidArgumentException + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException */ - public static function getSelectedTemplates( - $selectedExtension, $selectedTemplate, array $selectedLanguages, &$session, $siteRootId - ) { - $selectedTemplates = []; - + public static function saveTemplate($pid, $selectedExtension, $selectedTemplate, $language, $templateData) { $objectManager = GeneralUtility::makeInstance(ObjectManager::class); /** @var TemplateRepository $templateRepository */ $templateRepository = $objectManager->get(TemplateRepository::class); - $session->setDataByKey('selectedLanguageLeft', $selectedLanguages['left']); - $session->setDataByKey('selectedLanguageRight', $selectedLanguages['right']); - - $selectedTemplates['left'] = $templateRepository->findOneByTemplate( - $selectedExtension, $selectedTemplate, $selectedLanguages['left'], $siteRootId - ); - $selectedTemplates['right'] = $templateRepository->findOneByTemplate( - $selectedExtension, $selectedTemplate, $selectedLanguages['right'], $siteRootId + /** @var Template $template */ + $template = $templateRepository->findOneByTemplate( + $selectedExtension, $selectedTemplate, $language, $pid ); - return $selectedTemplates; + $templateAlreadyExists = TRUE; + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + if ($template === NULL) { + $templateAlreadyExists = FALSE; + $template = $objectManager->get(Template::class); + } + + $template->setExtensionKey($selectedExtension); + $template->setTemplateName($selectedTemplate); + $template->setLanguage($language); + $template->setContent($templateData['content']); + $template->setSubject($templateData['subject']); + $template->setFromName($templateData['fromName']); + $template->setFromMail($templateData['fromMail']); + $template->setCc($templateData['cc']); + $template->setBcc($templateData['bcc']); + $template->setReplyTo($templateData['replyTo']); + $template->setToAddress($templateData['toAddress']); + + if ($templateAlreadyExists) { + $templateRepository->update($template); + } else { + $templateRepository->add($template); + } + + return $template; } /** - * Get the translated subjects for the selected mail templates + * Generate a csv string from the queues, respecting the given filters * - * @param $subject - * @param $selectedExtension - * @param $selectedLanguages - * @return array + * @param array $filters + * @return string + * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException + * @throws \InvalidArgumentException */ - public static function getTranslatedTemplateSubject($subject, $selectedExtension, $selectedLanguages) { - $translatedSubjects = []; + public static function getCsvFromQueue(array $filters = []) { + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + /** @var MailRepository $mailRepository */ + $mailRepository = $objectManager->get(MailRepository::class); - $langFile = GeneralUtility::readLLfile( - 'EXT:' . $selectedExtension . '/Resources/Private/Language/locallang.xlf', $selectedLanguages['left'] - ); - $translatedSubjectLeft = $langFile['default'][$subject][0]['target']; - if ($langFile[$selectedLanguages['left']][$subject][0]) { - $translatedSubjectLeft = $langFile[$selectedLanguages['left']][$subject][0]['target']; - } - $translatedSubjects['left'] = $translatedSubjectLeft; + $pageUid = (int) GeneralUtility::_GP('id'); + /** @var array $queue */ + $queue = $mailRepository->findAllEntries($pageUid, 0, $filters); + $totalQueueSize = count($queue); + $exportString = ''; - $langFile = GeneralUtility::readLLfile( - 'EXT:' . $selectedExtension . '/Resources/Private/Language/locallang.xlf', $selectedLanguages['right'] - ); - $translatedSubjectRight = $langFile['default'][$subject][0]['target']; - if ($langFile[$selectedLanguages['right']][$subject][0]) { - $translatedSubjectRight = $langFile[$selectedLanguages['right']][$subject][0]['target']; + if ($totalQueueSize && $queue) { + $ignoreFields = ['uid', 'pid', 'tstamp', + 'password', 'starttime', 'endtime', 'deleted', 'sent', 'priority', 'crdate', 'cruser_id', 'hidden']; + $dateFields = ['tstamp', 'starttime', 'endtime', 'crdate']; + + $export = [[]]; + $first = TRUE; + + /** @var array $mail */ + foreach ($queue as $mail) { + if ($first) { + $first = FALSE; + foreach ($mail as $field => $value) { + if (!in_array($field, $ignoreFields, TRUE)) { + $label = isset($GLOBALS['TCA']['tx_sgmail_domain_model_mail']['columns'][$field]) ? + $GLOBALS['TCA']['fe_users']['columns'][$field]['label'] : ''; + if (strpos($label, 'LLL:') === 0) { + $label = $GLOBALS['LANG']->sL($label); + } + $export[0][] = $label ?: $field; + } + } + } + } + + $line = 1; + /** @var array $mail */ + foreach ($queue as $mail) { + foreach ($mail as $field => $value) { + if (!in_array($field, $ignoreFields, TRUE)) { + if (in_array($field, $dateFields, TRUE)) { + $export[$line][] = $value ? date('d.m.Y', $value) : ''; + } else { + $export[$line][] = (string) $value; + } + } + } + $line++; + } + + foreach ($export as $line) { + /** @var array $line */ + $fields = []; + foreach ($line as $field) { + $fields[] = '"' . $field . '"'; + } + $exportString .= implode(',', $fields) . ';' . LF; + } } - $translatedSubjects['right'] = $translatedSubjectRight; - return $translatedSubjects; + return trim(preg_replace('/\s\s+/', ' ', strip_tags($exportString))); } } diff --git a/Classes/Service/MailTemplateService.php b/Classes/Service/MailTemplateService.php index 43e483d631c74805d65613e98073e0e0ab49385f..df4be76b82762aceb7a5d906ff1396ce0a699d18 100644 --- a/Classes/Service/MailTemplateService.php +++ b/Classes/Service/MailTemplateService.php @@ -33,12 +33,16 @@ use SGalinski\SgMail\Domain\Repository\MailRepository; use SGalinski\SgMail\Domain\Repository\TemplateRepository; use Swift_Attachment; use Swift_OutputByteStream; +use TYPO3\CMS\Core\Cache\CacheManager; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\Mail\MailMessage; +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; use TYPO3\CMS\Fluid\View\StandaloneView; +use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; /** * MailTemplateService @@ -47,11 +51,10 @@ class MailTemplateService { const MARKER_TYPE_STRING = 'String'; const MARKER_TYPE_ARRAY = 'Array'; const MARKER_TYPE_OBJECT = 'Object'; - - /** - * @var array $registerArray - */ - private static $registerArray = []; + const DEFAULT_LANGUAGE = 'default'; + const DEFAULT_TEMPLATE_PATH = 'Resources/Private/Templates/SgMail/'; + const CACHE_NAME = 'sg_mail_registerArrayCache'; + const CACHE_LIFETIME_IN_SECONDS = 86400; /** * @var array $toAddresses @@ -76,7 +79,7 @@ class MailTemplateService { /** * @var string $language */ - private $language; + private $language = 'default'; /** * @var boolean $ignoreMailQueue @@ -101,14 +104,7 @@ class MailTemplateService { /** * @var array $markers */ - private $markers = []; - - /** - * holds the TypoScript configuration for sg_mail - * - * @var array $tsSettings - */ - private $tsSettings; + private $markers; /** * @var array $bccAddresses @@ -120,6 +116,11 @@ class MailTemplateService { */ private $priority = Mail::PRIORITY_LOWEST; + /** + * @var int + */ + private $pid; + /** * @var string */ @@ -143,26 +144,45 @@ class MailTemplateService { /** * MailTemplateService constructor. * + * @param string $templateName + * @param string $extensionKey + * @param string $markers * @throws \InvalidArgumentException */ - public function __construct() { + public function __construct($templateName = '', $extensionKey = '', $markers = '') { + $this->templateName = $templateName; + $this->extensionKey = $extensionKey; + $this->markers = $markers; + /** @var ObjectManager objectManager */ $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); /** @var MailMessage mailMessage */ $this->mailMessage = $this->objectManager->get(MailMessage::class); /** @var TypoScriptSettingsService $typoScriptSettingsService */ $typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class); - $this->tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail'); - $this->language = $this->tsSettings['templateDefaultLanguage']; + $tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail'); /** @var TemplateRepository templateRepository */ $this->templateRepository = $this->objectManager->get(TemplateRepository::class); /** @var PersistenceManager persistenceManager */ $this->persistenceManager = $this->objectManager->get(PersistenceManager::class); - $this->fromAddress = $this->tsSettings['mail']['default']['from']; + // use defaultMailFromAddress if it is provided in LocalConfiguration.php; use the sg_mail TS setting as fallback + if (!filter_var($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'], FILTER_VALIDATE_EMAIL)) { + $this->fromAddress = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress']; + } else { + $this->fromAddress = $tsSettings['mail']['default']['from']; + + if (!filter_var($tsSettings['mail']['default']['from'], FILTER_VALIDATE_EMAIL)) { + $this->fromAddress = 'noreply@example.org'; + } else { + $this->fromAddress = $tsSettings['mail']['default']['from']; + } + } + $this->mailMessage->setFrom($this->fromAddress); - $this->bccAddresses = GeneralUtility::trimExplode(',', $this->tsSettings['mail']['default']['bcc']); - $this->ccAddresses = GeneralUtility::trimExplode(',', $this->tsSettings['mail']['default']['cc']); + + $this->bccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['bcc']); + $this->ccAddresses = GeneralUtility::trimExplode(',', $tsSettings['mail']['default']['cc']); foreach ($this->bccAddresses as $index => $email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { @@ -185,59 +205,6 @@ class MailTemplateService { } } - /** - * register a template with sg_mail - * - * description and subject can now be an array i.e. with elements such as 'en' => 'english description' - * or an translation string used in locallang.xml - * - * @deprecated public usage of this function is deprecated. use registerByFile instead - * @param string $extension - * @param string $templateName - * @param string $templatePath - * @param mixed $description - * @param array $markers - * @param mixed $subject - * @param string $usage - */ - public static function registerTemplate( - $extension, $templateName, $templatePath, $description, array $markers, $subject, $usage = '' - ) { - MailTemplateService::$registerArray[$extension][$templateName] = [ - 'templatePath' => $templatePath, - 'description' => $description, - 'marker' => $markers, - 'extension' => $extension, - 'templateName' => $templateName, - 'subject' => $subject, - 'usage' => $usage - ]; - } - - /** - * call in extlocalconf of an extension if you have a custom register class - * - * @param RegisterInterface $fileNameWithNamespace - * @param boolean $initObject Should the object initialize itself ? - * - * @return bool - * @throws \InvalidArgumentException - */ - public static function registerByFile($fileNameWithNamespace, $initObject = TRUE) { - $registerObject = GeneralUtility::makeInstance($fileNameWithNamespace); - // check instance of interface - if (!($registerObject instanceof RegisterInterface)) { - return FALSE; - } - - // object calls registerTemplate, alternative way instead of localconf call - if ($initObject) { - $registerObject->init(); - } - $registerObject->registerTemplate(); - return TRUE; - } - /** * Return default markers for sg_mail * @@ -268,24 +235,28 @@ class MailTemplateService { return $generatedMarker; } - /** - * Get all registered templates - * - * @return array - */ - public static function getRegisterArray() { - return self::$registerArray; - } - /** * Send the Email * * @param boolean $isPreview * @return boolean email was sent or added to mail queue successfully? + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException + * @throws \InvalidArgumentException + * @throws \BadFunctionCallException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException */ public function sendEmail($isPreview = FALSE) { - $pageUid = (int) GeneralUtility::_GP('id'); + if (TYPO3_MODE === 'FE') { + /** @var TypoScriptFrontendController $tsfe */ + $tsfe = $GLOBALS['TSFE']; + $pageUid = $tsfe->id; + } else { + $pageUid = (int) GeneralUtility::_GP('id'); + } + + if ($this->pid) { + $pageUid = $this->pid; + } $siteRootId = BackendService::getSiteRoot($pageUid); /** @var Template $template */ @@ -293,34 +264,38 @@ class MailTemplateService { $this->extensionKey, $this->templateName, $this->language, $siteRootId ); + if ($template === NULL) { + $template = $this->templateRepository->findOneByTemplate( + $this->extensionKey, $this->templateName, 'default', $siteRootId + ); + } + // if there is a template, prefer those values if ($template) { $this->loadTemplateValues($template); } + $defaultTemplateContent = NULL; // If there is no template for this language, use the default template if ($template === NULL) { - $templatePath = self::$registerArray[$this->extensionKey][$this->templateName]['templatePath']; - $templateFile = $templatePath . $this->language . '.template.html'; - if (file_exists($templateFile)) { - $defaultTemplateContent = file_get_contents($templatePath . $this->language . '.template.html'); - } else { - // no language found and no default template - $this->setLanguage($this->tsSettings['templateDefaultLanguage'] ?: 'en'); - // does an english default template exist ? - if (file_exists($templatePath . $this->language . '.template.html')) { - $this->sendEmail(); - return TRUE; - } + $templatePath = self::getRegisterArray()[$this->extensionKey][$this->templateName]['templatePath']; + + // only standard template file is considered since version 4.1 + $defaultTemplateFile = $templatePath . 'template.html'; + if (file_exists($defaultTemplateFile)) { + $defaultTemplateContent = file_get_contents($defaultTemplateFile); + } else { return FALSE; } + } elseif (filter_var($template->getToAddress(), FILTER_VALIDATE_EMAIL)) { + $this->setToAddresses(trim($template->getToAddress())); } if ($isPreview) { $previewMarker = []; /** @var array $markerArray */ - $markerArray = self::$registerArray[$this->extensionKey][$this->templateName]['marker']; + $markerArray = self::getRegisterArray()[$this->extensionKey][$this->templateName]['marker']; foreach ($markerArray as $marker) { $markerPath = GeneralUtility::trimExplode('.', $marker['marker']); $temporaryMarkerArray = []; @@ -334,7 +309,7 @@ class MailTemplateService { $temporaryMarkerArray[$markerPathSegment] = $marker['value']; } } else { - $temporaryMarkerArray = [ $markerPathSegment => $temporaryMarkerArray]; + $temporaryMarkerArray = [$markerPathSegment => $temporaryMarkerArray]; } } $previewMarker = array_merge_recursive($previewMarker, $temporaryMarkerArray); @@ -352,12 +327,13 @@ class MailTemplateService { } else { $emailView->setTemplateSource($defaultTemplateContent); - $subject = self::$registerArray[$this->extensionKey][$this->templateName]['subject']; + $subject = self::getRegisterArray()[$this->extensionKey][$this->templateName]['subject']; if (is_array($subject)) { - $subject = self::$registerArray[$this->extensionKey][$this->templateName]['subject'][$this->language]; + $subject = self::getRegisterArray( + )[$this->extensionKey][$this->templateName]['subject'][$this->language]; } else { $subject = LocalizationUtility::translate( - self::$registerArray[$this->extensionKey][$this->templateName]['subject'], + self::getRegisterArray()[$this->extensionKey][$this->templateName]['subject'], $this->extensionKey ); } @@ -375,13 +351,22 @@ class MailTemplateService { $this->mailMessage->setBody($emailBody, 'text/html'); $this->mailMessage->send(); $dateTime = new DateTime(); - $this->addMailToMailQueue( - $this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority, - $dateTime->getTimestamp(), TRUE - ); + $currentTimestamp = $dateTime->getTimestamp(); + + if (!$isPreview) { + $this->addMailToMailQueue( + $this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority, + $currentTimestamp, $currentTimestamp, $this->language, $siteRootId + ); + } } else { - $this->addMailToMailQueue($this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority); + if (!$isPreview) { + $this->addMailToMailQueue( + $this->extensionKey, $this->templateName, $subject, $emailBody, $this->priority, 0, 0, + $this->language, $siteRootId + ); + } } return TRUE; @@ -396,31 +381,34 @@ class MailTemplateService { * @param string $emailBody * @param int $sendingTime * @param int $priority - * @param bool $sent + * @param int $lastSendingTime + * @param string $language + * @param int $pid * @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException */ private function addMailToMailQueue( - $extensionKey, $templateName, $subject, $emailBody, $priority, $sendingTime = 0, $sent = FALSE + $extensionKey, $templateName, $subject, $emailBody, $priority, $sendingTime = 0, + $lastSendingTime = 0, $language = self::DEFAULT_LANGUAGE, $pid = 0 ) { $mail = $this->objectManager->get(Mail::class); + $mail->setPid($pid); $mail->setExtensionKey($extensionKey); $mail->setTemplateName($templateName); + $mail->setLanguage($language); + $mail->setFromAddress($this->fromAddress); $mail->setFromName($this->fromName); + $mail->setToAddress($this->toAddresses); $mail->setMailSubject($subject); $mail->setMailBody($emailBody); $mail->setPriority($priority); $mail->setBccAddresses($this->bccAddresses); $mail->setCcAddresses($this->ccAddresses); - $mail->setSent($sent); $mail->setSendingTime($sendingTime); + $mail->setLastSendingTime($lastSendingTime); $mail->setReplyTo($this->replyToAddress); - $pageUid = (int) GeneralUtility::_GP('id'); - $siteRootId = BackendService::getSiteRoot($pageUid); - $mail->setSiteRootId($siteRootId); - $mailRepository = $this->objectManager->get(MailRepository::class); $mailRepository->add($mail); $this->persistenceManager->persistAll(); @@ -439,9 +427,8 @@ class MailTemplateService { $mailToSend = $mailRepository->findOneByUid($uid); if ($mailToSend) { - $this->mailMessage->setBody($mailToSend->getMailBody(), 'text/html'); - $this->mailMessage->setTo($mailToSend->getToAddress()); + $this->mailMessage->setTo(trim($mailToSend->getToAddress())); $this->mailMessage->setFrom($mailToSend->getFromAddress(), $mailToSend->getFromName()); $this->mailMessage->setSubject($mailToSend->getMailSubject()); @@ -457,30 +444,21 @@ class MailTemplateService { $this->mailMessage->setReplyTo($mailToSend->getReplyTo()); } + $dateTime = new DateTime(); + $mailToSend->setLastSendingTime($dateTime->getTimestamp()); $this->mailMessage->send(); - - if (!$mailToSend->getSent()) { - $mailToSend->setSent(TRUE); - $mailRepository->update($mailToSend); - } + $mailRepository->update($mailToSend); } } - /** - * @param array $registerArray - * @return void - */ - public static function setRegisterArray(array $registerArray) { - self::$registerArray = $registerArray; - } - /** * @param string $toAddresses * @return MailTemplateService */ public function setToAddresses($toAddresses) { - $this->toAddresses = $toAddresses; - $this->mailMessage->setTo($toAddresses); + $toAddresses = preg_replace('~\x{00a0}~siu',' ', $toAddresses); + $this->toAddresses = trim($toAddresses); + $this->mailMessage->setTo(trim($toAddresses)); return $this; } @@ -619,11 +597,24 @@ class MailTemplateService { * @param Template $template */ private function loadTemplateValues($template) { - $this->setFromAddress($template->getFromMail(), $template->getFromName()); + $fromName = $template->getFromName(); + if ($fromName === '' && $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']) { + $fromName = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']; + } + + $fromMail = $template->getFromMail(); + if (!filter_var($fromMail, FILTER_VALIDATE_EMAIL)) { + $fromMail = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress']; + if (!filter_var($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'], FILTER_VALIDATE_EMAIL)) { + $fromMail = 'noreply@example.com'; + } + } + + $this->setFromAddress($fromMail, $fromName); $this->setCcAddresses($template->getCc()); $this->setBccAddresses($template->getBcc()); $this->setReplyToAddress($template->getReplyTo()); - $this->setFromName($template->getFromName()); + $this->setFromName($fromName); $this->setReplyToAddress($template->getReplyTo()); } @@ -654,4 +645,99 @@ class MailTemplateService { LocalizationUtility::translate('backend.marker.type.mixed', 'sg_mail'); } } + + /** + * set the page id from which this was called + * + * @param int $pid + * @return MailTemplateService + */ + public function setPid($pid) { + $this->pid = (int) $pid; + return $this; + } + + /** + * Get all registered templates + * + * @return array + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException + * @throws \BadFunctionCallException + * @throws \InvalidArgumentException + */ + public static function getRegisterArray() { + /** @var CacheManager $cacheManager */ + $cacheManager = GeneralUtility::makeInstance(CacheManager::class); + /** @var FrontendInterface $cache */ + $cache = $cacheManager->getCache(self::CACHE_NAME); + $cacheId = md5('sg_mail'); + /** @var array entry */ + if (($entry = $cache->get($cacheId)) === FALSE) { + $entry = self::registerExtensions(); + + if ($entry === NULL) { + $entry = []; + } + + $cache->set($cacheId, $entry, [], self::CACHE_LIFETIME_IN_SECONDS); + } + + return $entry; + } + + /** + * Iterate over all installed extensions and look for sg_mail configuration files + * If found, register the template(s) + * + * @throws \BadFunctionCallException + * @return array + */ + public static function registerExtensions() { + // clear registerArray + $registerArray = []; + + $extensionList = ExtensionManagementUtility::getLoadedExtensionListArray(); + + foreach ($extensionList as $extensionName) { + $extensionConfigDirectory = ExtensionManagementUtility::extPath($extensionName); + $extensionConfigDirectory .= '/Configuration/MailTemplates'; + $configFiles = GeneralUtility::getFilesInDir($extensionConfigDirectory); + + foreach ($configFiles as $configFile) { + $configArray = (include $extensionConfigDirectory . '/' . $configFile); + $extensionKey = $configArray['extension_key']; + $templateKey = $configArray['template_key']; + + // transform template directory name: your_templates => YourTemplates/ + $templateDirectoryParts = GeneralUtility::trimExplode('_', $configArray['template_key']); + $templateDirectory = ''; + foreach ($templateDirectoryParts as $part) { + $templateDirectory .= ucfirst($part); + } + $templateDirectory .= '/'; + $templatePath = ExtensionManagementUtility::extPath( + $extensionName + ) . self::DEFAULT_TEMPLATE_PATH . $templateDirectory; + + if ($configArray['template_path']) { + $templatePath = $configArray['template_key']; + } + + $description = $configArray['description']; + $subject = $configArray['subject']; + $marker = $configArray['markers']; + + $registerArray[$extensionKey][$templateKey] = [ + 'templatePath' => $templatePath, + 'description' => $description, + 'marker' => $marker, + 'extension' => $extensionKey, + 'templateName' => $templateKey, + 'subject' => $subject + ]; + } + } + + return $registerArray; + } } diff --git a/Classes/Session/PhpSession.php b/Classes/Session/PhpSession.php index 6babbd7838dd691dbe86cd2ffd26a42f4cb63041..501f603010484e3f030faec56e2f2dfa4417c4d8 100644 --- a/Classes/Session/PhpSession.php +++ b/Classes/Session/PhpSession.php @@ -42,7 +42,7 @@ class PhpSession implements SingletonInterface { */ public function __construct() { session_start(); - $this->sessionKey = uniqid(); + $this->sessionKey = uniqid('sgalinski', TRUE); } /** diff --git a/Classes/Updates/UpdateGermanAsDefault.php b/Classes/Updates/UpdateGermanAsDefault.php new file mode 100644 index 0000000000000000000000000000000000000000..c907cba39f31f3544255f7f0838fe368cd4e3de0 --- /dev/null +++ b/Classes/Updates/UpdateGermanAsDefault.php @@ -0,0 +1,109 @@ +<?php + +namespace SGalinski\SgMail\Updates; + +/*************************************************************** + * Copyright notice + * + * (c) sgalinski Internet Services (https://www.sgalinski.de) + * + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +use TYPO3\CMS\Core\Database\DatabaseConnection; +use TYPO3\CMS\Install\Updates\AbstractUpdate; + +/** + * Makes german templates the default and former default as english templates + */ +class UpdateGermanAsDefault extends AbstractUpdate { + /** + * @var string + */ + protected $title = 'Makes german templates the default and former default as english templates. WARNING: ONLY EXECUTE THIS IF IT MAKES SENSE FOR YOUR TYPO3 INSTANCE'; + + /** + * @var \TYPO3\CMS\Extbase\Object\ObjectManager + */ + protected $objectManager; + + /** + * @var string + */ + protected $table = 'tx_sgmail_domain_model_template'; + + /** + * Checks whether updates are required. + * + * @param string &$description The description for the update + * @return bool Whether an update is required (TRUE) or not (FALSE) + */ + public function checkForUpdate(&$description) { + $description = 'Update if there are german templates'; + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + + // are there sent emails ? + $where = 'language ="de"'; + + $result = $databaseConnection->exec_SELECTquery('*', $this->table, $where); + if ($result->num_rows > 0) { + return TRUE; + } + + return !(!FALSE || $this->isWizardDone()); + } + + /** + * Performs the according updates. + * + * @param array &$dbQueries Queries done in this update + * @param mixed &$customMessages Custom messages + * @return bool Whether everything went smoothly or not + */ + public function performUpdate(array &$dbQueries, &$customMessages) { + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + $dbQueries = []; + $where = 'language = "de"'; + $resultGerman = $databaseConnection->exec_SELECTquery('uid', $this->table, $where)->fetch_all(); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + + $where = 'language = "default"'; + $resultDefault = $databaseConnection->exec_SELECTquery('uid', $this->table, $where)->fetch_all(); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + + /** @var array $resultGerman */ + foreach ($resultGerman as $row) { + $where = 'uid = ' . $row[0]; + $databaseConnection->exec_UPDATEquery($this->table, $where, ['language' => 'default']); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + } + + /** @var array $resultGerman */ + foreach ($resultDefault as $row) { + $where = 'uid = ' . $row[0]; + $databaseConnection->exec_UPDATEquery($this->table, $where, ['language' => 'en']); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + } + + $this->markWizardAsDone(); + return TRUE; + } +} diff --git a/Classes/Updates/UpdateLanguages.php b/Classes/Updates/UpdateLanguages.php new file mode 100644 index 0000000000000000000000000000000000000000..7bdfdfe50c9f1ec57ebf94308c67c2abb7dd7ba2 --- /dev/null +++ b/Classes/Updates/UpdateLanguages.php @@ -0,0 +1,130 @@ +<?php + +namespace SGalinski\SgMail\Updates; + +/*************************************************************** + * Copyright notice + * + * (c) sgalinski Internet Services (https://www.sgalinski.de) + * + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +use SGalinski\SgMail\Service\BackendService; +use TYPO3\CMS\Core\Database\DatabaseConnection; +use TYPO3\CMS\Install\Updates\AbstractUpdate; + +/** + * Fix all incorrect / deprecated language codes (be languages instead of sys languages) in the database + */ +class UpdateLanguages extends AbstractUpdate { + /** + * @var string + */ + protected $title = 'Find all templates & queue entries with an incorrect (be languages instead of sys languages) language code and fix it'; + + /** + * @var \TYPO3\CMS\Extbase\Object\ObjectManager + */ + protected $objectManager; + + /** + * @var array + */ + protected $tables = [ + 'tx_sgmail_domain_model_mail', 'tx_sgmail_domain_model_template' + ]; + + /** + * is used to map language codes. If empty the updatewizard will ignore this update + * example: you want to change en-us to en + * [ + * 'en-us' => 'en' + * ] + * + * @var array + */ + protected $languageMap = [ + + ]; + + /** + * Checks whether updates are required. + * + * @param string &$description The description for the update + * @return bool Whether an update is required (TRUE) or not (FALSE) + * @throws \InvalidArgumentException + */ + public function checkForUpdate(&$description) { + $upgradeNecessary = FALSE; + + if (count($this->languageMap) > 0) { + $languages = BackendService::getLanguages(); + $where = 'language NOT IN ('; + foreach ($languages as $language) { + $where .= '"' . $language['isocode'] . '",'; + } + $where = rtrim($where, ','); + $where .= ')'; + + $description = 'Check all the language codes in the database'; + + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $this->getDatabaseConnection(); + + foreach ($this->tables as $table) { + /** @var \mysqli_result $result */ + $result = $databaseConnection->exec_SELECTquery('distinct language', $table, $where); + if ($result->num_rows > 0) { + $upgradeNecessary = TRUE; + break; + } + } + } + + return !(!$upgradeNecessary || $this->isWizardDone()); + } + + /** + * Performs the accordant updates. + * + * @param array &$dbQueries Queries done in this update + * @param mixed &$customMessages Custom messages + * @return bool Whether everything went smoothly or not + */ + public function performUpdate(array &$dbQueries, &$customMessages) { + $dbQueries = []; + + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $this->getDatabaseConnection(); + + foreach ($this->tables as $table) { + foreach ($this->languageMap as $origin => $target) { + $where = 'language = ' . $origin; + $databaseConnection->exec_UPDATEquery($table, $where, [ + 'language' => $target + ]); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + } + } + + $this->markWizardAsDone(); + return TRUE; + } +} diff --git a/Classes/Updates/UpdatePidToSiteRoot.php b/Classes/Updates/UpdatePidToSiteRoot.php new file mode 100644 index 0000000000000000000000000000000000000000..8f7ec69046d3c8a7fec8b24b2f39fe0625e01dfa --- /dev/null +++ b/Classes/Updates/UpdatePidToSiteRoot.php @@ -0,0 +1,169 @@ +<?php + +namespace SGalinski\SgMail\Updates; + +/*************************************************************** + * Copyright notice + * + * (c) sgalinski Internet Services (https://www.sgalinski.de) + * + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +use SGalinski\SgMail\Service\BackendService; +use TYPO3\CMS\Core\Database\DatabaseConnection; +use TYPO3\CMS\Install\Updates\AbstractUpdate; + +/** + * Migrate template db entries to the correct root pages + */ +class UpdatePidToSiteRoot extends AbstractUpdate { + /** + * @var string + */ + protected $title = 'Find all templates & queue entries with site root and assign the correct site root id as pid. Also check if the pids are actually site roots and update them accordingly'; + + /** + * @var \TYPO3\CMS\Extbase\Object\ObjectManager + */ + protected $objectManager; + + /** + * @var array + */ + protected $tables = [ + 'tx_sgmail_domain_model_mail', 'tx_sgmail_domain_model_template' + ]; + + /** + * Checks whether updates are required. + * + * @param string &$description The description for the update + * @return bool Whether an update is required (TRUE) or not (FALSE) + */ + public function checkForUpdate(&$description) { + $description = 'Move site root ids to pid & update pids to their correspondent site root ids'; + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + + // check if site_root columns actually exist + $hasColumn = []; + foreach ($this->tables as $table) { + $hasColumn[$table] = $this->siteRootColumnExists($table); + } + + // are there site root columns differing from pids? + $where = 'site_root_id <> pid'; + foreach ($this->tables as $table) { + if (!$hasColumn[$table]) { + continue; + } + $result = $databaseConnection->exec_SELECTquery('*', $table, $where); + if ($result->num_rows > 0) { + return TRUE; + break; + } + } + + // are the pids not belonging to site root pages ? + foreach ($this->tables as $table) { + $result = $databaseConnection->exec_SELECTquery('pid', $table, '')->fetch_all(); + foreach ($result as $row) { + $siteRootId = BackendService::getSiteRoot($row[0]); + if ($siteRootId !== $row[0]) { + return TRUE; + } + } + } + + return !(!FALSE || $this->isWizardDone()); + } + + /** + * Performs the according updates. + * + * @param array &$dbQueries Queries done in this update + * @param mixed &$customMessages Custom messages + * @return bool Whether everything went smoothly or not + */ + public function performUpdate(array &$dbQueries, &$customMessages) { + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + $dbQueries = []; + + // set pids to siteroot + foreach ($this->tables as $table) { + if (!$this->siteRootColumnExists($table)) { + continue; + } + + $result = $databaseConnection->exec_SELECTquery('uid, site_root_id', $table, '')->fetch_all(); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + + /** @var array $result */ + foreach ($result as $row) { + $where = 'uid = ' . $row[0]; + $databaseConnection->exec_UPDATEquery($table, $where, ['pid' => $row[1]]); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + } + } + + // check if pid is a site root, if not update it to the nearest one + foreach ($this->tables as $table) { + $result = $databaseConnection->exec_SELECTquery('uid, pid', $table, '')->fetch_all(); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + + /** @var array $result */ + foreach ($result as $row) { + $siteRootId = BackendService::getSiteRoot($row[1]); + if ($siteRootId === 0) { + $siteRootId = 1; + } + if ($siteRootId !== (int) $row[1]) { + $where = 'uid = ' . $row[0]; + $databaseConnection->exec_UPDATEquery($table, $where, ['pid' => $siteRootId]); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + } + } + } + + $this->markWizardAsDone(); + return TRUE; + } + + /** + * check if site_root columns actually exist + * + * @param $table + * @return bool + */ + private function siteRootColumnExists($table) { + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + $result = $databaseConnection->admin_get_fields($table); + + foreach ($result as $column) { + if ($column['Field'] === 'site_root_id') { + return TRUE; + } + } + + return FALSE; + } +} diff --git a/Classes/Updates/UpdateSendingTimes.php b/Classes/Updates/UpdateSendingTimes.php new file mode 100644 index 0000000000000000000000000000000000000000..97ab7935a2a908d3343c1203141c84cecbde9760 --- /dev/null +++ b/Classes/Updates/UpdateSendingTimes.php @@ -0,0 +1,98 @@ +<?php + +namespace SGalinski\SgMail\Updates; + +/*************************************************************** + * Copyright notice + * + * (c) sgalinski Internet Services (https://www.sgalinski.de) + * + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +use TYPO3\CMS\Core\Database\DatabaseConnection; +use TYPO3\CMS\Install\Updates\AbstractUpdate; + +/** + * Update the correct sending times (if any) + */ +class UpdateSendingTimes extends AbstractUpdate { + /** + * @var string + */ + protected $title = 'Find all sent mails and set the sending time to the tstamp field'; + + /** + * @var \TYPO3\CMS\Extbase\Object\ObjectManager + */ + protected $objectManager; + + /** + * @var string + */ + protected $table = 'tx_sgmail_domain_model_mail'; + + /** + * Checks whether updates are required. + * + * @param string &$description The description for the update + * @return bool Whether an update is required (TRUE) or not (FALSE) + */ + public function checkForUpdate(&$description) { + $description = 'Update the sending times if mails have been sent'; + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + + // are there sent emails ? + $where = 'sending_time > 0 AND last_sending_time = 0'; + + $result = $databaseConnection->exec_SELECTquery('*', $this->table, $where); + if ($result->num_rows > 0) { + return TRUE; + } + + return !(!FALSE || $this->isWizardDone()); + } + + /** + * Performs the according updates. + * + * @param array &$dbQueries Queries done in this update + * @param mixed &$customMessages Custom messages + * @return bool Whether everything went smoothly or not + */ + public function performUpdate(array &$dbQueries, &$customMessages) { + /** @var DatabaseConnection $databaseConnection */ + $databaseConnection = $GLOBALS['TYPO3_DB']; + $dbQueries = []; + $where = 'sending_time > 0 AND last_sending_time = 0'; + $result = $databaseConnection->exec_SELECTquery('uid, sending_time', $this->table, $where)->fetch_all(); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + + /** @var array $result */ + foreach ($result as $row) { + $where = 'uid = ' . $row[0]; + $databaseConnection->exec_UPDATEquery($this->table, $where, ['last_sending_time' => $row[1]]); + $dbQueries[] = $databaseConnection->debug_lastBuiltQuery; + } + + $this->markWizardAsDone(); + return TRUE; + } +} diff --git a/Configuration/TCA/tx_sgmail_domain_model_mail.php b/Configuration/TCA/tx_sgmail_domain_model_mail.php index 783c433aac929be8ffecb09871423b62fc160dc9..0c73381011312149e03b027a3c3836b9d687a330 100644 --- a/Configuration/TCA/tx_sgmail_domain_model_mail.php +++ b/Configuration/TCA/tx_sgmail_domain_model_mail.php @@ -32,21 +32,21 @@ return [ 'tstamp' => 'tstamp', 'crdate' => 'crdate', 'cruser_id' => 'cruser_id', - 'searchFields' => 'mail_subject, mail_body, to_address, from_address, from_name, bcc_addresses, cc_addresses, extension_key, template_name, site_root_id', + 'searchFields' => 'mail_subject, mail_body, to_address, from_address, from_name, bcc_addresses, cc_addresses, extension_key, template_name, sending_time, last_sending_time, language', 'dividers2tabs' => TRUE, 'delete' => 'deleted', 'enablecolumns' => [ 'disabled' => 'hidden', ], - 'default_sortby' => 'ORDER BY sent ASC, priority DESC', + 'default_sortby' => 'ORDER BY priority DESC', 'iconfile' => 'EXT:sg_mail/Resources/Public/Icons/ModuleIconTCA.svg' ], 'interface' => [ - 'showRecordFieldList' => 'hidden, mail_subject, mail_body, to_address, from_address, sent, priority, from_name, bcc_addresses, cc_addresses, extension_key, template_name, site_root_id', + 'showRecordFieldList' => 'hidden, mail_subject, mail_body, to_address, from_address, priority, from_name, bcc_addresses, cc_addresses, extension_key, template_name, sending_time, last_sending_time, language', ], 'types' => [ '1' => [ - 'showitem' => 'hidden;;1, sent, priority, to_address, from_address, mail_subject, mail_body, from_name, bcc_addresses, cc_addresses, extension_key, template_name, site_root_id' + 'showitem' => 'hidden;;1, priority, to_address, from_address, mail_subject, mail_body, from_name, bcc_addresses, cc_addresses, extension_key, template_name, sending_time, last_sending_time, language' ], ], 'columns' => [ @@ -91,13 +91,6 @@ return [ 'eval' => 'required, email' ], ], - 'sent' => [ - 'exclude' => TRUE, - 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_mail.sent', - 'config' => [ - 'type' => 'check', - ], - ], 'priority' => [ 'exclude' => TRUE, 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_mail.priority', @@ -151,6 +144,13 @@ return [ 'type' => 'input' ], ], + 'last_sending_time' => [ + 'exclude' => TRUE, + 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_mail.last_sending_time', + 'config' => [ + 'type' => 'input' + ], + ], 'reply_to' => [ 'exclude' => TRUE, 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_mail.reply_to', @@ -158,12 +158,12 @@ return [ 'type' => 'input' ], ], - 'site_root_id' => [ + 'language' => [ 'exclude' => TRUE, - 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_mail.site_root_id', + 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_mail.language', 'config' => [ 'type' => 'input', - 'eval' => 'int' + 'eval' => 'required, trim' ], ] ] diff --git a/Configuration/TCA/tx_sgmail_domain_model_template.php b/Configuration/TCA/tx_sgmail_domain_model_template.php index 52f3a352ff53333906d0d963a80e4c645afda03a..3ff152ab419f62a45d411122ef19b704e374cdbf 100644 --- a/Configuration/TCA/tx_sgmail_domain_model_template.php +++ b/Configuration/TCA/tx_sgmail_domain_model_template.php @@ -33,7 +33,7 @@ return [ 'tstamp' => 'tstamp', 'crdate' => 'crdate', 'cruser_id' => 'cruser_id', - 'searchFields' => 'extension_key, template_name, language, subject, fromName, fromMail, replyTo, site_root_id', + 'searchFields' => 'extension_key, template_name, language, subject, fromName, fromMail, replyTo, to_address', 'dividers2tabs' => TRUE, 'delete' => 'deleted', 'enablecolumns' => [ @@ -43,11 +43,11 @@ return [ 'iconfile' => 'EXT:sg_mail/Resources/Public/Icons/ModuleIconTCA.svg' ], 'interface' => [ - 'showRecordFieldList' => 'extension_key, template_name, language, content, subject, fromName, fromMail, cc, bcc, replyTo, site_root_id' + 'showRecordFieldList' => 'extension_key, template_name, language, content, subject, fromName, fromMail, cc, bcc, replyTo, to_address' ], 'types' => [ '1' => [ - 'showitem' => 'hidden;;1, extension_key, template_name, language, content, subject, fromName, fromMail, cc, bcc, replyTo, site_root_id' + 'showitem' => 'hidden;;1, extension_key, template_name, language, content, subject, fromName, fromMail, cc, bcc, replyTo, to_address' ], ], 'columns' => [ @@ -134,12 +134,11 @@ return [ 'type' => 'input' ], ], - 'site_root_id' => [ + 'to_address' => [ 'exclude' => TRUE, - 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_template.site_root_id', + 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_template.toAddress', 'config' => [ - 'type' => 'input', - 'eval' => 'int' + 'type' => 'input' ], ] ] diff --git a/README.md b/README.md index 6e35543f3370fcf5efcf0da34f9845b9f00b0a49..6d5557a7efdd0a8370b7bfebd01c398148c00b54 100644 --- a/README.md +++ b/README.md @@ -17,54 +17,112 @@ It also supports Templates in various languages, which can be managed in the bac Additionally sg_mail provides a finisher class for the [Formhandler](https://typo3.org/extensions/repository/view/formhandler) extension, making it possible to manage its templates in the backend. +sg_mail ist multi-site and multi-language ready. ## Usage ### Registering your Extension -To make sg_mail available for your extension, you have to register it inside your **ext_localconf.php** -by supplying a path string to an implementation of **SGalinski\SgMail\Service\RegisterInterface** with: +To register your extension with sg_mail, you need a **Configuration File** for each template you want to integrate. +It needs be a *.php* file and has to be inside the Configuration folder **typo3conf/ext/{your_extension}/Configuration** of your extension. +The naming of the file should be in upper camel case, matching your template name. -* your extension key -* a name for the template -* the path to your default template files (template files should be named *language_code*.template.html. Example: en.template.html) -* a brief description of the template (when is it used ?) -* the template markers(placeholder variables) -* the subjects for all templates. Here you have to use an associative array language_code => subject +sg_mail will automatically parse valid configuration files of all extensions within your TYPO3 instance. -**Example** : +Inside the file you have mandatory and optional settings you can define: -A fully working example class can be found here: **SGalinski\SgMail\Example\Register** +**Mandatory** -All you need to do to get the example to work is registering your class in **ext_localconf.php** with: +- extension_key + Needed to associate this template with the appropriate extension, - \SGalinski\SgMail\Service\MailTemplateService::registerByFile('SGalinski\SgMail\Example\Register'); + +- template_key + A unique identifier of your template. + + +- description + A short description of your templates usage, displayed in the backend template editor. This should be a **language label** + + +- subject + The default mail subject used for this Template. Here you can also provide a language label. + + +- markers +An array of placeholder variables. Are dynamically replaced by the appropriate values. If you don't want any markers, provide an empty array. + +A marker needs to be structured as follows: + +- marker + The variables name used in your templates. + +- type + Here you can specify the variable type by using one of the constants in the **\SGalinski\SgMail\Service\MailTemplateService** class. + +- value + An example value of this marker. Also used for previewing your mails in the backend module. + +- description + A short text describing the purpose of this marker. + + +**Optional** + +- template_path + You can provide a path to your mail template that differs from the default path with this setting. + +**The template folder** +If not overwritten in your configuration file, the default location for your extensions templates is **ext/sg_example/Resources/Private/Templates/SgMail/{TemplateNameInUpperCamelCase}**. +Inside this folder you need a folder for every template you want to register. The name of the template file itself should be **template.html** + +**Example:** + +Your configuration file for the template "confirm_mail" should be located at **../Configuration/ConfirmMail.php**. + +A possible ConfirmMail.php file could look like this: + + return [ + 'extension_key' => 'sg_example', + 'template_key' => 'confirm_mail', + 'description' => 'LLL:EXT:sg_example/Resources/Private/Language/locallang.xlf:mail.confirm.description', + 'subject' => 'LLL:EXT:sg_example/Resources/Private/Language/locallang.xlf:mail.confirm.subject', + 'markers' => [ + [ + 'marker' => 'username', + 'type' => \SGalinski\SgMail\Service\MailTemplateService::MARKER_TYPE_STRING, + 'value' => 'max.mustermann@example.org', + 'description' => 'LLL:EXT:sg_energieportal/Resources/Private/Language/locallang.xlf:mail.marker.username' + ], + .... // more markers + ] + ]; + +The default path to the template.html file: ext/sg_example/Resources/Private/Templates/SgMail/ConfirmMail ### Send an email with the MailTemplateService Basic Usage: 1. Get an instance of MailTemplateService -2. Set all desired fields (i.e. setLanguage, setToAddresses, setTemplateName, setExtensionKey etc.) -3. Invoke the **sendEmail()** function +2. Provide the **template_name**, **extension_key** and marker array in the constructor +3. Set or override all desired fields (i.e. setLanguage, setToAddresses, setTemplateName, setExtensionKey etc.) +4. Invoke the **sendEmail()** function Example: // get an instance of the service /** @var MailTemplateService $mailService */ - $mailService = $this->objectManager->get(MailTemplateService::class); + $mailService = $this->objectManager->get(MailTemplateService::class, 'confirm_mail', sg_example', ['username' => $username]); - // set the extension key & template name (mandatory!) - $mailService->setExtensionKey('your_extension_key'); - $mailService->setTemplateName($this->settings['templateName']); - - // set all the custom fields, these fields all have fallbacks from your configuration or the code $mailService->setFromName($this->settings['fromName']); $mailService->setFromAddress($this->settings['fromEmail']); $mailService->setToAddresses([$emailAddress]); $mailService->setIgnoreMailQueue(TRUE); - $mailService->setMarkers(['link' => $uri]); - // set the proper language for the mail + // set the pageId (mandatory since version 4.0!!!) + $mailService->setPid(123); + + // set the proper language for the mail (not necessary if you want the default language) $mailService->setLanguage($GLOBALS['TSFE']->config['config']['language']); // finally send the mail @@ -94,6 +152,13 @@ Go to your scheduler module in the TYPO3 Backend and setup a scheduled CommandCo For more information on the TYPO3 scheduler extension read its [manual](https://docs.typo3.org/typo3cms/extensions/scheduler/Index.html). +## Language handling + +When you provide no language to the MailService API, the default language of the TYPO3 instance is used. +This happens also if the given iso code of the language is not known (inside the **sys_lang** table). + +In your template editor you have automatically all languages of your page shown. + ## Using sg_mail with Formhandler In your **setup.txt** of your formhandler extension, you have to invoke the **FormhandlerFinisherService** of sg_mail. @@ -145,6 +210,7 @@ With the **Mail Queue** mode, you can see the current content of your mailing qu <br> <img height="20px" width="20px" src="https://camo.githubusercontent.com/4b1188209e740e17a4ec0cd6583425696809017b/68747470733a2f2f7261776769742e636f6d2f5459504f332f5459504f332e49636f6e732f6d61737465722f646973742f616374696f6e732f616374696f6e732d646f63756d656e742d766965772e737667"> View the content of this mail +Additionally you can now filter the mail queue or export it to a csv file. ## Developer Guide @@ -164,84 +230,14 @@ This extension uses two database tables: The extbase model classes for these tables are located at the *Domain\Model* folder. ### Service Classes -##### Register Interface -To register your extension you need at least one implementation of this interface. -Inside the **init()** function of your Implementation you should define variables for the following purposes: - -###### Template Key -A unique Identifier for this particular template. It should be obvious from the template key for what purpose this template is intended. - -###### Extension Key -The extension key of the TYPO3 extension registering with sg_mail. This should be the same for all of your extensions! - -###### Description -A brief description about the template, visible in the backend module - -###### subject -The default subject text for the emails. It is possible to specify language specific texts with an associative array: - - [ - 'en' => 'english subject', - 'de' => 'german subject', - ... - ] - -###### markers -This is an array of information for substitute variables that are used to replace certain values at runtime. - -Each Array element should be its own array and structured like this: - - [ - 'marker' => 'marker_name', - 'type' => \SGalinski\SgMail\Service\MailTemplateService::MARKER_TYPE_STRING, - 'value' => 'some value', - 'description' => 'This marker is used for X in the email' - ] - -marker = the variable name you use in the template -type = the date type of the variable -value = an example value, visible in the backend to the editors -description = a brief description for what this variable is intended for - -Finally you have to call the function **\SGalinski\SgMail\Service\MailTemplateService::registerTemplate** (this is only marked deprecated for public use) -inside your **register()** function and pass all the necessary values. - -Now you can register the class in your **ext_localconf.php** with - - \SGalinski\SgMail\Service\MailTemplateService::registerByFile('SGalinski\SgMail\Example\Register'); - - -You find a complete example of this process in the file **SGalinski\SgMail\Example\Register** - ---- #### MailTemplateService This class provides you with an API to the mailing functionality and various helper functions regarding the your templates. Here is an overview of some important functions: -###### function registerTemplate -A static function that adds your template to the service. Should be called from within your **Register** class (see **RegisterInterface**). - -###### function registerByFile -Registers a template by providing a complete class name of your **RegisterInterface** implementation as an argument. -Needs to be called from within your **ext_localconf.php**. - ###### function getDefaultTemplateMarker Reads custom example template marker from your **locallang.xlf**. This is only useful if you need multi language examples in your Backend Marker - -###### function getRegisterArray -Returns an array of all registered templates, with each element in the following format: - - [ - 'templatePath' => '/path/to/template', - 'description' => 'description of the template', - 'marker' => $arrayOfMarkers, - 'extension' => 'extension_key', - 'templateName' => 'unique_template_name', - 'subject' => 'The mail subject', - 'usage' => 'optional description of this templates usage' - ] ###### function loadPredefinedValuesForTemplate Sets the predefined values for this template that have been supplied by the editor. Use this method if you have no custom values for @@ -253,10 +249,6 @@ Sends your mail or adds it to the mailing queue, depending on the settings. You ###### function sendMailFromQueue Forces the sending of an E-Mail from within the queue. If it has already been sent, it gets send again. -###### function setRegisterArray -Enables you to overwrite the register array. This overwrites **ALL** registered templates with the supplied data -and should be handled with care. - ###### function addAttachment With this function you can add attachments to your mail. The attachment must be of type *Swift_OutputByteStream*. You must also specify the content-type of the attachment. diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf index b7185689e75c42d6a425abc0ad46a7f7d013acbe..3e6a366ea0ca749597804220f5078680d6f4def8 100644 --- a/Resources/Private/Language/de.locallang.xlf +++ b/Resources/Private/Language/de.locallang.xlf @@ -9,17 +9,29 @@ <authorEmail>torsten@sgalinski.de</authorEmail> </header> <body> + <trans-unit id="backend.all" approved="yes"> + <source>All</source> + <target>Alle</target> + </trans-unit> <trans-unit id="backend.bcc" approved="yes"> <source>BCC (Blind Carbon Copy Receiver, comma separated)</source> <target>BCC (Blindempfänger, komma-separiert)</target> </trans-unit> + <trans-unit id="backend.button_download_csv" approved="yes"> + <source>Export CSV</source> + <target>CSV exportieren</target> + </trans-unit> <trans-unit id="backend.button_reset" approved="yes"> <source>Reset Template</source> <target>Zurücksetzen</target> </trans-unit> <trans-unit id="backend.button_reset_all" approved="yes"> - <source>Reset all languages for this template(!!!)</source> - <target>Alle Sprachen für dieses Template zurücksetzen(!!!)</target> + <source>Reset template</source> + <target>Template zurücksetzen</target> + </trans-unit> + <trans-unit id="backend.button_reset_filter" approved="yes"> + <source>Reset</source> + <target>Zurücksetzen</target> </trans-unit> <trans-unit id="backend.cc" approved="yes"> <source>CC (Carbon Copy Receiver, comma separated)</source> @@ -41,10 +53,90 @@ <source>Email</source> <target>E-Mail</target> </trans-unit> + <trans-unit id="backend.entry_date" approved="yes"> + <source>Queue Entry Date</source> + <target>Erstellungsdatum</target> + </trans-unit> + <trans-unit id="backend.error_bcc" approved="yes"> + <source>The bcc addresses are invalid</source> + <target>Ungültige Blindempfänger Adressen (bcc)</target> + </trans-unit> + <trans-unit id="backend.error_cc" approved="yes"> + <source>The cc addresses are invalid</source> + <target>Ungültige Kopieempfänger Adressen (cc)</target> + </trans-unit> <trans-unit id="backend.failure_mail" approved="yes"> <source>There was an error when sending the preview email. Please check your configuration.</source> <target>Ein Fehler ist aufgetreten. Bitte überprüfen Sie die Konfiguration.</target> </trans-unit> + <trans-unit id="backend.filter.bcc" approved="yes"> + <source>BCC address</source> + <target>BCC Adressen</target> + </trans-unit> + <trans-unit id="backend.filter.cc" approved="yes"> + <source>CC address</source> + <target>CC Adressen</target> + </trans-unit> + <trans-unit id="backend.filter.date_from" approved="yes"> + <source>Last sent time since:</source> + <target>Zuletzt gesendet von:</target> + </trans-unit> + <trans-unit id="backend.filter.date_to" approved="yes"> + <source>Last sent until:</source> + <target>Zuletzt gesendet bis:</target> + </trans-unit> + <trans-unit id="backend.filter.extension" approved="yes"> + <source>Extension</source> + <target>Extension</target> + </trans-unit> + <trans-unit id="backend.filter.fields.description" approved="yes"> + <source>Search fields (all by default):</source> + <target>Suchfelder (standardmäßig alle):</target> + </trans-unit> + <trans-unit id="backend.filter.filter" approved="yes"> + <source>Filter</source> + <target>Filter anwenden</target> + </trans-unit> + <trans-unit id="backend.filter.from" approved="yes"> + <source>Sender address</source> + <target>Absender</target> + </trans-unit> + <trans-unit id="backend.filter.from_name" approved="yes"> + <source>From name</source> + <target>Absendername</target> + </trans-unit> + <trans-unit id="backend.filter.language" approved="yes"> + <source>Language:</source> + <target>Sprache:</target> + </trans-unit> + <trans-unit id="backend.filter.mailtext" approved="yes"> + <source>Mailtext</source> + <target>Mailinhalt</target> + </trans-unit> + <trans-unit id="backend.filter.reply_to" approved="yes"> + <source>Reply to</source> + <target>Antwort Adresse</target> + </trans-unit> + <trans-unit id="backend.filter.search" approved="yes"> + <source>Search for:</source> + <target>Suchen nach:</target> + </trans-unit> + <trans-unit id="backend.filter.subject" approved="yes"> + <source>Subject</source> + <target>Betreff</target> + </trans-unit> + <trans-unit id="backend.filter.template" approved="yes"> + <source>Template</source> + <target>Template</target> + </trans-unit> + <trans-unit id="backend.filter.to" approved="yes"> + <source>Recipient address</source> + <target>Empfänger</target> + </trans-unit> + <trans-unit id="backend.from" approved="yes"> + <source>From</source> + <target>Absender</target> + </trans-unit> <trans-unit id="backend.fromAddress" approved="yes"> <source>Sender Email Address</source> <target>Absender-E-Mail-Adresse</target> @@ -57,6 +149,22 @@ <source>Sender Name</source> <target>Absender-Name</target> </trans-unit> + <trans-unit id="backend.fromUser" approved="yes"> + <source>From User (overwrites other from fields):</source> + <target>Absender Benutzer (hat Vorrang falls gesetzt):</target> + </trans-unit> + <trans-unit id="backend.is_overwritten" approved="yes"> + <source>(overwritten)</source> + <target>(überschrieben)</target> + </trans-unit> + <trans-unit id="backend.language_default" approved="yes"> + <source>Default</source> + <target>Standard</target> + </trans-unit> + <trans-unit id="backend.last_sent" approved="yes"> + <source>Last Sent</source> + <target>Zuletzt gesendet</target> + </trans-unit> <trans-unit id="backend.mail_queue" approved="yes"> <source>Mail Queue</source> <target>Mail-Queue</target> @@ -81,9 +189,17 @@ <source>No template was registered.</source> <target>Es wurde noch kein Template registriert.</target> </trans-unit> + <trans-unit id="backend.no_extensions" approved="yes"> + <source>No extensions registered</source> + <target>Es wurden noch keine Extensions registriert</target> + </trans-unit> <trans-unit id="backend.no_queue_entries" approved="yes"> - <source>There are no entries in the mail queue for this template.</source> - <target>Es gibt keine Einträge für dieses Template.</target> + <source>Your filter criteria didn't match any entries.</source> + <target>Es wurden keine Einträge für Ihre Filtereinstellungen gefunden.</target> + </trans-unit> + <trans-unit id="backend.no_site_root" approved="yes"> + <source>Please select one of the following website roots:</source> + <target>Bitte wählen Sie eine der folgenden Webseiten:</target> </trans-unit> <trans-unit id="backend.not_sent" approved="yes"> <source>Not Sent</source> @@ -109,6 +225,10 @@ <source>Language (reloads the page):</source> <target>Sprache (lädt die Seite neu):</target> </trans-unit> + <trans-unit id="backend.send_again" approved="yes"> + <source>Send</source> + <target>Senden</target> + </trans-unit> <trans-unit id="backend.send_mail_again" approved="yes"> <source>Send this email again?</source> <target>Diese E-Mail nochmals versenden?</target> @@ -117,9 +237,13 @@ <source>Send this email now?</source> <target>Diese E-Mail jetzt versenden?</target> </trans-unit> + <trans-unit id="backend.send_now" approved="yes"> + <source>Send</source> + <target>Senden</target> + </trans-unit> <trans-unit id="backend.send_test" approved="yes"> - <source>Send Preview Mail (Save First!)</source> - <target>Sende Vorschau-Mail (Bitte vorher speichern!)</target> + <source>Save and send preview mails</source> + <target>Speichern und Vorschau-Mail senden</target> </trans-unit> <trans-unit id="backend.sending_time" approved="yes"> <source>Sending Time</source> @@ -130,8 +254,8 @@ <target>Versendet</target> </trans-unit> <trans-unit id="backend.showBody" approved="yes"> - <source>Show Mail</source> - <target>Mail anzeigen</target> + <source>Show</source> + <target>Anzeigen</target> </trans-unit> <trans-unit id="backend.subject" approved="yes"> <source>Subject</source> @@ -142,8 +266,8 @@ <target>Erfolgreich gespeichert!</target> </trans-unit> <trans-unit id="backend.success_mail" approved="yes"> - <source>Preview Email sent</source> - <target>Vorschau-E-Mail wurde versendet</target> + <source>Preview Emails sent</source> + <target>Vorschau E-Mails wurden versendet</target> </trans-unit> <trans-unit id="backend.success_mail_queue" approved="yes"> <source>Email succesfully sent</source> @@ -161,21 +285,29 @@ <source>The template was resetted successfully.</source> <target>Das Template erfolgreich zurückgesetzt.</target> </trans-unit> + <trans-unit id="backend.to_form" approved="yes"> + <source>To (If set, this overwrites the recipient everytime!) </source> + <target>Empfänger (Falls angegeben, wird der Empfänger immer überschrieben!)</target> + </trans-unit> + <trans-unit id="backend.to" approved="yes"> + <source>To</source> + <target>Empfänger</target> + </trans-unit> <trans-unit id="backend.toAddress" approved="yes"> <source>Receiver</source> <target>Empfänger</target> </trans-unit> <trans-unit id="backend.type" approved="yes"> - <source>Marker Type</source> - <target>Marker-Typ</target> + <source>Type</source> + <target>Typ</target> </trans-unit> <trans-unit id="backend.usage" approved="yes"> <source>Usage in Template</source> <target>Nutzung im Template</target> </trans-unit> <trans-unit id="backend.value" approved="yes"> - <source>Example Value</source> - <target>Beispielwert</target> + <source>Example</source> + <target>Beispiel</target> </trans-unit> <trans-unit id="mlang_labels_tabdescr" approved="yes"> <source>Mail Templates</source> diff --git a/Resources/Private/Language/de.locallang_db.xlf b/Resources/Private/Language/de.locallang_db.xlf index 665c0138b72c681cc6f2f788fcc1be5462e8c494..373333d319a51a3ca12385cebdea3d4e5163e6be 100644 --- a/Resources/Private/Language/de.locallang_db.xlf +++ b/Resources/Private/Language/de.locallang_db.xlf @@ -33,6 +33,14 @@ <source>Sender Name</source> <target>Absender-Name</target> </trans-unit> + <trans-unit id="tx_sgmail_domain_model_mail.language" approved="yes"> + <source>Language</source> + <target>Sprache</target> + </trans-unit> + <trans-unit id="tx_sgmail_domain_model_mail.last_sending_time" approved="yes"> + <source>Last sent</source> + <target>Letzer Versand</target> + </trans-unit> <trans-unit id="tx_sgmail_domain_model_mail.mail_body" approved="yes"> <source>Mail text</source> <target>Mail-Text</target> @@ -125,6 +133,10 @@ <source>Template Name</source> <target>Template-Name</target> </trans-unit> + <trans-unit id="tx_sgmail_domain_model_template.toAddress" approved="yes"> + <source>To Address</source> + <target>Empfänger Adresse</target> + </trans-unit> </body> </file> </xliff> \ No newline at end of file diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 0be092f81e92cd76b5ee02ea2fcb9b8686267cb2..a981af7ee20890b6f367efea941fb9088ec8e38b 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -9,14 +9,23 @@ <authorEmail>torsten@sgalinski.de</authorEmail> </header> <body> + <trans-unit id="backend.all"> + <source>All</source> + </trans-unit> <trans-unit id="backend.bcc"> <source>BCC (Blind Carbon Copy Receiver, comma separated)</source> </trans-unit> + <trans-unit id="backend.button_download_csv"> + <source>Export CSV</source> + </trans-unit> <trans-unit id="backend.button_reset"> <source>Reset Template</source> </trans-unit> <trans-unit id="backend.button_reset_all"> - <source>Reset all languages for this template(!!!)</source> + <source>Reset template</source> + </trans-unit> + <trans-unit id="backend.button_reset_filter"> + <source>Reset</source> </trans-unit> <trans-unit id="backend.cc"> <source>CC (Carbon Copy Receiver, comma separated)</source> @@ -33,9 +42,69 @@ <trans-unit id="backend.email"> <source>Email</source> </trans-unit> + <trans-unit id="backend.entry_date"> + <source>Queue Entry Date</source> + </trans-unit> + <trans-unit id="backend.error_bcc"> + <source>The bcc addresses are invalid</source> + </trans-unit> + <trans-unit id="backend.error_cc"> + <source>The cc addresses are invalid</source> + </trans-unit> <trans-unit id="backend.failure_mail"> <source>There was an error when sending the preview email. Please check your configuration.</source> </trans-unit> + <trans-unit id="backend.filter.bcc"> + <source>BCC address</source> + </trans-unit> + <trans-unit id="backend.filter.cc"> + <source>CC address</source> + </trans-unit> + <trans-unit id="backend.filter.date_from"> + <source>Last sent time since:</source> + </trans-unit> + <trans-unit id="backend.filter.date_to"> + <source>Last sent until:</source> + </trans-unit> + <trans-unit id="backend.filter.extension"> + <source>Extension</source> + </trans-unit> + <trans-unit id="backend.filter.fields.description"> + <source>Search fields (all by default):</source> + </trans-unit> + <trans-unit id="backend.filter.filter"> + <source>Filter</source> + </trans-unit> + <trans-unit id="backend.filter.from"> + <source>Sender address</source> + </trans-unit> + <trans-unit id="backend.filter.from_name"> + <source>From name</source> + </trans-unit> + <trans-unit id="backend.filter.language"> + <source>Language:</source> + </trans-unit> + <trans-unit id="backend.filter.mailtext"> + <source>Mailtext</source> + </trans-unit> + <trans-unit id="backend.filter.reply_to"> + <source>Reply to</source> + </trans-unit> + <trans-unit id="backend.filter.search"> + <source>Search for:</source> + </trans-unit> + <trans-unit id="backend.filter.subject"> + <source>Subject</source> + </trans-unit> + <trans-unit id="backend.filter.template"> + <source>Template</source> + </trans-unit> + <trans-unit id="backend.filter.to"> + <source>Recipient address</source> + </trans-unit> + <trans-unit id="backend.from"> + <source>From</source> + </trans-unit> <trans-unit id="backend.fromAddress"> <source>Sender Email Address</source> </trans-unit> @@ -45,6 +114,18 @@ <trans-unit id="backend.fromName"> <source>Sender Name</source> </trans-unit> + <trans-unit id="backend.fromUser"> + <source>From User (overwrites other from fields):</source> + </trans-unit> + <trans-unit id="backend.is_overwritten"> + <source>(overwritten)</source> + </trans-unit> + <trans-unit id="backend.language_default"> + <source>Default</source> + </trans-unit> + <trans-unit id="backend.last_sent"> + <source>Last Sent</source> + </trans-unit> <trans-unit id="backend.mail_queue"> <source>Mail Queue</source> </trans-unit> @@ -63,8 +144,14 @@ <trans-unit id="backend.no_extension"> <source>No template was registered.</source> </trans-unit> + <trans-unit id="backend.no_extensions"> + <source>No extensions registered</source> + </trans-unit> <trans-unit id="backend.no_queue_entries"> - <source>There are no entries in the mail queue for this template.</source> + <source>Your filter criteria didn't match any entries.</source> + </trans-unit> + <trans-unit id="backend.no_site_root"> + <source>Please select one of the following website roots:</source> </trans-unit> <trans-unit id="backend.not_sent"> <source>Not Sent</source> @@ -84,14 +171,20 @@ <trans-unit id="backend.select_language"> <source>Language (reloads the page):</source> </trans-unit> + <trans-unit id="backend.send_again"> + <source>Send</source> + </trans-unit> <trans-unit id="backend.send_mail_again"> <source>Send this email again?</source> </trans-unit> <trans-unit id="backend.send_mail_manually"> <source>Send this email now?</source> </trans-unit> + <trans-unit id="backend.send_now"> + <source>Send</source> + </trans-unit> <trans-unit id="backend.send_test"> - <source>Send Preview Mail (Save First!)</source> + <source>Save and send preview mails</source> </trans-unit> <trans-unit id="backend.sending_time"> <source>Sending Time</source> @@ -100,7 +193,7 @@ <source>Sent</source> </trans-unit> <trans-unit id="backend.showBody"> - <source>Show Mail</source> + <source>Show</source> </trans-unit> <trans-unit id="backend.subject"> <source>Subject</source> @@ -109,7 +202,7 @@ <source>Successfully saved!</source> </trans-unit> <trans-unit id="backend.success_mail"> - <source>Preview Email sent</source> + <source>Preview Emails sent</source> </trans-unit> <trans-unit id="backend.success_mail_queue"> <source>Email succesfully sent</source> @@ -123,17 +216,23 @@ <trans-unit id="backend.template_reset"> <source>The template was resetted successfully.</source> </trans-unit> + <trans-unit id="backend.to_form"> + <source>To (If set, this overwrites the recipient everytime!) </source> + </trans-unit> + <trans-unit id="backend.to"> + <source>To</source> + </trans-unit> <trans-unit id="backend.toAddress"> <source>Receiver</source> </trans-unit> <trans-unit id="backend.type"> - <source>Marker Type</source> + <source>Type</source> </trans-unit> <trans-unit id="backend.usage"> <source>Usage in Template</source> </trans-unit> <trans-unit id="backend.value"> - <source>Example Value</source> + <source>Example</source> </trans-unit> <trans-unit id="mlang_labels_tabdescr"> <source>Mail Templates</source> diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf index 59049aae939e3ea1cfb1beac711043b186a07478..7412be39c6f0b975ad35fcbee83f922ecae5c883 100644 --- a/Resources/Private/Language/locallang_db.xlf +++ b/Resources/Private/Language/locallang_db.xlf @@ -27,6 +27,12 @@ <trans-unit id="tx_sgmail_domain_model_mail.from_name"> <source>Sender Name</source> </trans-unit> + <trans-unit id="tx_sgmail_domain_model_mail.language"> + <source>Language</source> + </trans-unit> + <trans-unit id="tx_sgmail_domain_model_mail.last_sending_time"> + <source>Last sent</source> + </trans-unit> <trans-unit id="tx_sgmail_domain_model_mail.mail_body"> <source>Mail text</source> </trans-unit> @@ -96,6 +102,9 @@ <trans-unit id="tx_sgmail_domain_model_template.template_name"> <source>Template Name</source> </trans-unit> + <trans-unit id="tx_sgmail_domain_model_template.toAddress"> + <source>To Address</source> + </trans-unit> </body> </file> </xliff> \ No newline at end of file diff --git a/Resources/Private/Layouts/Default.html b/Resources/Private/Layouts/Default.html index 69b3e2d59aae7b0ff73d2d9364b9cd5033165245..31f7f7e13502c23542d08077739dbdab31cfef35 100644 --- a/Resources/Private/Layouts/Default.html +++ b/Resources/Private/Layouts/Default.html @@ -9,106 +9,116 @@ <div class="module" data-module-id="" data-module-name=""> <div class="module-docheader t3js-module-docheader"> <div class="module-docheader-bar module-docheader-bar-navigation t3js-module-docheader-bar t3js-module-docheader-bar-navigation"> - <div class="module-docheader-bar-column-left"> - <f:be.menus.actionMenu> - <f:if condition="{mode} == 'queue'"> - <f:then> - <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.mail_queue')}" - controller="Queue" - action="index" - arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" - additionalAttributes="{selected: 'selected'}" /> - </f:then> - <f:else> - <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.mail_queue')}" - controller="Queue" - action="index" - arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" /> - </f:else> - </f:if> - <f:if condition="{mode} == 'editor'"> - <f:then> - <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.template_editor')}" - controller="Mail" - action="index" - arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" - additionalAttributes="{selected: 'selected'}" /> - </f:then> - <f:else> - <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.template_editor')}" - controller="Mail" - action="index" - arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" /> - </f:else> - </f:if> - </f:be.menus.actionMenu> - </div> - <div class="module-docheader-bar-column-right"> - <span class="typo3-docheader-pagePath"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw></span> - <f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw> - </div> - </div> - <div class="module-docheader-bar module-docheader-bar-buttons t3js-module-docheader-bar t3js-module-docheader-bar-buttons"> - <div class="module-docheader-bar-column-left"> - <div class="btn-toolbar" role="toolbar" aria-label=""> - <f:if condition="{templates}"> + <f:if condition="{pages}"> + <f:then></f:then> + <f:else> + <div class="module-docheader-bar-column-left"> <f:be.menus.actionMenu> - <f:for each="{templates}" as="template" key="extensionKey"> - <f:if condition="{mode} == 'queue'"> - <sgm:be.menus.actionMenuOptionGroup label="{extensionKey}"> - <f:for each="{template}" as="currentTemplate" key="templateKey"> - <sgm:extendedIf condition="{selectedTemplateKey} == {templateKey}" - and="{selectedExtensionKey} == {extensionKey}"> - <f:then> - <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" - controller="Queue" - action="index" - arguments="{selectedTemplate: templateKey, selectedExtension: extensionKey}" - additionalAttributes="{selected: 'selected'}" /> - </f:then> - <f:else> - <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" - controller="Queue" - action="index" - arguments="{selectedTemplate: templateKey, selectedExtension: extensionKey}" /> - </f:else> - </sgm:extendedIf> - </f:for> - </sgm:be.menus.actionMenuOptionGroup> - </f:if> + <f:if condition="{mode} == 'queue'"> + <f:then> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.mail_queue')}" + controller="Queue" + action="index" + arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" + additionalAttributes="{selected: 'selected'}" /> + </f:then> <f:else> - <f:if condition="{mode} == 'editor'"> - <sgm:be.menus.actionMenuOptionGroup label="{extensionKey}"> - <f:for each="{template}" as="currentTemplate" key="templateKey"> - <sgm:extendedIf condition="{selectedTemplateKey} == {templateKey}" - and="{selectedExtensionKey} == {extensionKey}"> - <f:then> - <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" - controller="Mail" - action="index" - arguments="{selectedTemplate: templateKey, selectedExtension: extensionKey}" - additionalAttributes="{selected: 'selected'}" /> - </f:then> - <f:else> - <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" - controller="Mail" - action="index" - arguments="{selectedTemplate: templateKey, selectedExtension: extensionKey}" /> - </f:else> - </sgm:extendedIf> - </f:for> - </sgm:be.menus.actionMenuOptionGroup> - </f:if> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.mail_queue')}" + controller="Queue" + action="index" + arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" /> </f:else> - </f:for> + </f:if> + <f:if condition="{mode} == 'editor'"> + <f:then> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.template_editor')}" + controller="Mail" + action="index" + arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" + additionalAttributes="{selected: 'selected'}" /> + </f:then> + <f:else> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.template_editor')}" + controller="Mail" + action="index" + arguments="{selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}" /> + </f:else> + </f:if> </f:be.menus.actionMenu> - </f:if> - </div> - </div> + </div> + </f:else> + </f:if> <div class="module-docheader-bar-column-right"> - <f:render partial="ButtonBar" arguments="{buttons:docHeader.buttons.right}" /> + <span class="typo3-docheader-pagePath"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw></span> + <f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw> </div> </div> + <f:if condition="{pages}"> + <f:then></f:then> + <f:else> + <div class="module-docheader-bar module-docheader-bar-buttons t3js-module-docheader-bar t3js-module-docheader-bar-buttons"> + <div class="module-docheader-bar-column-left"> + <div class="btn-toolbar" role="toolbar" aria-label=""> + <f:if condition="{templates}"> + <f:be.menus.actionMenu> + <f:for each="{templates}" as="template" key="extensionKey"> + <f:if condition="{mode} == 'queue'"> + <sgm:be.menus.actionMenuOptionGroup label="{extensionKey}"> + <f:for each="{template}" as="currentTemplate" key="templateKey"> + <sgm:extendedIf condition="{selectedTemplateKey} == {templateKey}" + and="{selectedExtensionKey} == {extensionKey}"> + <f:then> + <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" + controller="Queue" + action="index" + arguments="{parameters: {selectedTemplate: templateKey, selectedExtension: extensionKey}}" + additionalAttributes="{selected: 'selected'}" /> + </f:then> + <f:else> + <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" + controller="Queue" + action="index" + arguments="{parameters: {selectedTemplate: templateKey, selectedExtension: extensionKey}}" /> + </f:else> + </sgm:extendedIf> + </f:for> + </sgm:be.menus.actionMenuOptionGroup> + </f:if> + <f:else> + <f:if condition="{mode} == 'editor'"> + <sgm:be.menus.actionMenuOptionGroup label="{extensionKey}"> + <f:for each="{template}" as="currentTemplate" key="templateKey"> + <sgm:extendedIf condition="{selectedTemplateKey} == {templateKey}" + and="{selectedExtensionKey} == {extensionKey}"> + <f:then> + <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" + controller="Mail" + action="index" + arguments="{parameters: {selectedTemplate: templateKey, selectedExtension: extensionKey}}" + additionalAttributes="{selected: 'selected'}" /> + </f:then> + <f:else> + <sgm:be.menus.actionMenuItem label="{currentTemplate.templateName}" + controller="Mail" + action="index" + arguments="{parameters: {selectedTemplate: templateKey, selectedExtension: extensionKey}}" /> + </f:else> + </sgm:extendedIf> + </f:for> + </sgm:be.menus.actionMenuOptionGroup> + </f:if> + </f:else> + </f:for> + </f:be.menus.actionMenu> + </f:if> + </div> + </div> + <div class="module-docheader-bar-column-right"> + <f:render partial="ButtonBar" arguments="{buttons:docHeader.buttons.right}" /> + </div> + </div> + </f:else> + </f:if> </div> </div> <div id="typo3-docbody"> diff --git a/Resources/Private/Layouts/Empty.html b/Resources/Private/Layouts/Empty.html new file mode 100644 index 0000000000000000000000000000000000000000..83a0a701ca112a2a5b38a11195a25d6c7815a5cf --- /dev/null +++ b/Resources/Private/Layouts/Empty.html @@ -0,0 +1,8 @@ +{namespace sgm=SGalinski\SgMail\ViewHelpers} +<f:be.container> + <div id="typo3-docbody"> + <div id="typo3-inner-docbody"> + <f:render section="content" /> + </div> + </div> +</f:be.container> diff --git a/Resources/Private/Layouts/Queue.html b/Resources/Private/Layouts/Queue.html new file mode 100644 index 0000000000000000000000000000000000000000..2469fe2bed49c9bd43f6afadde5738df802b3fbf --- /dev/null +++ b/Resources/Private/Layouts/Queue.html @@ -0,0 +1,64 @@ +{namespace sgm=SGalinski\SgMail\ViewHelpers} +<f:be.container enableClickMenu="FALSE" loadExtJs="TRUE" loadJQuery="TRUE" includeCssFiles="{0: '{f:uri.resource(path: \'StyleSheets/backend.css\')}'}" + includeRequireJsModules="{ + 0: 'TYPO3/CMS/Backend/AjaxDataHandler', + 1: '{f:if(condition: \'{typo3Version} < 8000000 \', then: \'TYPO3/CMS/Backend/ClickMenu\', else: \'TYPO3/CMS/Backend/ContextMenu\')}', + 2: 'TYPO3/CMS/Backend/Tooltip', + 3: 'TYPO3/CMS/Backend/DateTimePicker'}"> + <sgm:addJavaScriptFile javaScriptFile="{f:uri.resource(path: 'Scripts/Backend.js')}" /> + <sgm:inlineLanguageLabels labels="backend.delete_template, backend.send_mail_manually, backend.send_mail_again" /> + <div class="module" data-module-id="" data-module-name=""> + <div class="module-docheader t3js-module-docheader"> + <div class="module-docheader-bar module-docheader-bar-navigation t3js-module-docheader-bar t3js-module-docheader-bar-navigation"> + <f:if condition="{pages}"> + <f:then></f:then> + <f:else> + <div class="module-docheader-bar-column-left"> + <f:be.menus.actionMenu> + <f:if condition="{mode} == 'queue'"> + <f:then> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.mail_queue')}" + controller="Queue" + action="index" + additionalAttributes="{selected: 'selected'}" + arguments="{parameters: {selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}}" /> + </f:then> + <f:else> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.mail_queue')}" + controller="Queue" + action="index" + arguments="{parameters: {selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}}" /> + </f:else> + </f:if> + <f:if condition="{mode} == 'editor'"> + <f:then> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.template_editor')}" + controller="Mail" + action="index" + arguments="{parameters: {selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}}" + additionalAttributes="{selected: 'selected'}" /> + </f:then> + <f:else> + <sgm:be.menus.actionMenuItem label="{f:translate(key:'backend.template_editor')}" + controller="Mail" + action="index" + arguments="{parameters: {selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}}" /> + </f:else> + </f:if> + </f:be.menus.actionMenu> + </div> + </f:else> + </f:if> + <div class="module-docheader-bar-column-right"> + <span class="typo3-docheader-pagePath"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw></span> + <f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw> + </div> + </div> + </div> + </div> + <div id="typo3-docbody"> + <div id="typo3-inner-docbody"> + <f:render section="content" /> + </div> + </div> +</f:be.container> diff --git a/Resources/Private/Partials/Mail/Empty.html b/Resources/Private/Partials/Mail/Empty.html index bd24155f49f5de299cc565e9bb18912562222e7b..00da31387f53280c02abe166cd4b380ffef57fc6 100644 --- a/Resources/Private/Partials/Mail/Empty.html +++ b/Resources/Private/Partials/Mail/Empty.html @@ -1,3 +1,5 @@ -<p> - {f:translate(key:'backend.no_extension')} -</p> +<div class="row"> + <p> + <h3>{f:translate(key:'backend.no_site_root')}</h3> + </p> +</div> diff --git a/Resources/Private/Partials/Queue/Filter.html b/Resources/Private/Partials/Queue/Filter.html new file mode 100644 index 0000000000000000000000000000000000000000..eb7a405a97ab4ebbba61bf99f8c55831bd9e801e --- /dev/null +++ b/Resources/Private/Partials/Queue/Filter.html @@ -0,0 +1,130 @@ +{namespace sgm=SGalinski\SgMail\ViewHelpers} +<f:form action="index" controller="Queue" method="post" objectName="filters" object="{filters}"> + <div class="row"> + <div class="col-xs-12 col-md-4"> + <div class="form-group"> + <label for="filter-search"><f:translate key="backend.filter.search" /></label> + <f:form.textfield class="reset-me form-control" property="filterSearch" id="filter-search" /> + </div> + <div class="form-group"> + <label for="filterTemplate"><f:translate key="backend.filter.template" /></label> + <f:comment> + <f:form.select class="form-control" multiple="0" size="1" property="filterTemplate" optionValueField="key" options="{templatesFilter}" id="filter-template" /> + </f:comment> + + <select class="form-control" property="filterTemplate" id="filterTemplate" name="filterTemplate"> + <f:for each="{templatesFilter}" as="extension" key="extensionKey"> + <f:if condition="{extensionKey}"> + <f:then> + <sgm:be.menus.actionMenuOptionGroup label="{extensionKey}"> + <f:for each="{extension}" as="template"> + <sgm:extendedIf condition="{selectedTemplateFilter} == {template}" + and="{selectedExtensionFilter} == {extensionKey}"> + <f:then> + <option value="{extensionKey}###{template}" selected="selected"> + {template} + </option> + </f:then> + <f:else> + <option value="{extensionKey}###{template}"> + {template} + </option> + </f:else> + </sgm:extendedIf> + </f:for> + </sgm:be.menus.actionMenuOptionGroup> + </f:then> + <f:else> + <option></option> + </f:else> + </f:if> + + </f:for> + </select> + </div> + <div class="form-group"> + <label for="filter-languages"><f:translate key="backend.filter.language" /></label> + <f:form.select class="form-control" multiple="0" size="1" property="filterLanguage" optionValueField="key" options="{languages}" id="filter-languages" /> + </div> + </div> + <div class="col-xs-12 col-md-4"> + <div class="form-group"> + <label for="filter-fields"> + <f:translate key="backend.filters.fields" /> + <f:translate key="backend.filter.fields.description" /> + </label> + <f:form.select class="form-control" multiple="1" size="9" property="filterFields" optionValueField="value" options="{filterFields}" id="filter-fields" /> + </div> + </div> + <div class="col-xs-12 col-md-4"> + + <div class="input-group form-group" style="width: 100%; display: block;"> + <label for="filter-to-date"> + <f:translate key="backend.filter.date_from" /> + </label> + <div class="form-control-clearable"> + <f:form.textfield property="filterFromDate" id="filter-from-date" data="{date-type: 'datetime'}" class="reset-me form-control t3js-datetimepicker t3js-clearable hasDefaultValue" /> + <button type="button" class="close" tabindex="-1" aria-hidden="true" style="display: none;"> + <span class="fa fa-times"></span> + </button> + </div> + <span class="input-group-btn"> + <label class="btn btn-default" for="filter-from-date"> + <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-edit-pick-date" data-identifier="actions-edit-pick-date"> + <span class="icon-markup"> + <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-edit-pick-date.svg" width="16" height="16"> + </span> + </span> + </label> + </span> + </div> + <div class="input-group form-group" style="width: 100%; display: block;"> + <label for="filter-to-date"> + <f:translate key="backend.filter.date_to" /> + </label> + <div class="form-control-clearable"> + <f:form.textfield property="filterToDate" id="filter-to-date" data="{date-type: 'datetime'}" class="reset-me form-control t3js-datetimepicker t3js-clearable hasDefaultValue" /> + <button type="button" class="close" tabindex="-1" aria-hidden="true" style="display: none;"> + <span class="fa fa-times"></span> + </button> + </div> + <span class="input-group-btn"> + <label class="btn btn-default" for="filter-to-date"> + <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-edit-pick-date" data-identifier="actions-edit-pick-date"> + <span class="icon-markup"> + <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-edit-pick-date.svg" width="16" height="16"> + </span> + </span> + </label> + </span> + </div> + <div class="form-group"> + <label class="radio-inline"> + <f:form.radio property="filterSent" id="filters-all" value="0" checked="{f:if(condition: '{filters.filterSent} == \'0\'', then: '1')}" /> + <f:translate key="backend.all" /> + </label> + <label class="radio-inline"> + <f:form.radio property="filterSent" id="filters-sent" value="1" checked="{f:if(condition: '{filters.filterSent} == \'1\'', then: '1')}" /> + <f:translate key="backend.sent" /> + </label> + <label class="radio-inline"> + <f:form.radio property="filterSent" id="filters-notsent" value="2" checked="{f:if(condition: '{filters.filterSent} == \'2\'', then: '1')}" /> + <f:translate key="backend.not_sent" /> + </label> + </div> + <div class="form-group row"> + <div class="col-md-12"> + <f:form.button class="filter-btn btn btn-success form-group col-xs-12 col-md-12" type="submit"> + <f:translate key="backend.filter.filter" /> + </f:form.button> + <f:form.button class="filter-btn btn btn-info form-group col-xs-12 col-md-12" type="submit" name="action" value="export"> + <f:translate key="backend.button_download_csv" /> + </f:form.button> + <f:form.button id="filter-reset-btn" class="filter-btn btn btn-danger form-group col-xs-12 col-md-12" type="reset"> + <f:translate key="backend.button_reset_filter" /> + </f:form.button> + </div> + </div> + </div> + </div> +</f:form> diff --git a/Resources/Private/Templates/Mail/Empty.html b/Resources/Private/Templates/Mail/Empty.html new file mode 100644 index 0000000000000000000000000000000000000000..c39bf8639ddeb268eb99722aa1d9e5fd0e764c19 --- /dev/null +++ b/Resources/Private/Templates/Mail/Empty.html @@ -0,0 +1,7 @@ +<f:layout name="Empty" /> + +<f:section name="content"> + <div class="alert alert-warning"> + {f:translate(key:'backend.no_extensions')} + </div> +</f:section> diff --git a/Resources/Private/Templates/Mail/Index.html b/Resources/Private/Templates/Mail/Index.html index 00a638f7fbd4fa596bb1fc3a1946197741f56f19..479c7d7e4df3e53a1852c46074e904c5f38315f6 100644 --- a/Resources/Private/Templates/Mail/Index.html +++ b/Resources/Private/Templates/Mail/Index.html @@ -6,204 +6,168 @@ </f:section> <f:section name="content"> <f:flashMessages /> + <br /> <f:if condition="{selectedTemplate}"> <f:then> - <div class="form-group col-md-6"> - <p>{templateDescription}</p> - </div> - <div class="form-group col-md-2 col-md-offset-3"> - <f:link.action class="reset-btn reset-all-btn btn-danger btn form-group" action="reset" arguments="{template: selectedTemplateKey, extensionKey: selectedTemplate.extension}">{f:translate(key:'backend.button_reset_all')}</f:link.action> - </div> - <div class="col-md-12"> - <table class="table table-hover"> - <thead> - <tr> - <th><f:translate key="backend.marker" /></th> - <th><f:translate key="backend.type" /></th> - <th><f:translate key="backend.value" /></th> - <th><f:translate key="backend.usage" /></th> - <th><f:translate key="backend.description" /></th> - </tr> - </thead> - <f:for each="{selectedTemplate.marker}" as="marker"> - <tr> - <td>{marker.marker}</td> - <td> - <f:if condition="{marker.type}"> - <f:then> - <f:translate key="{marker.type}">{marker.type}</f:translate> - </f:then> - <f:else> - <f:translate key="backend.marker.type.string" /> - </f:else> - </f:if> - </td> - <td> - <f:if condition="{sgm:isArray(value: '{marker.value}')}"> - <f:then> - <f:for each="{marker.value}" as="value" key="key"> - {key}: {value} - <br /> - </f:for> - </f:then> - <f:else> - <f:translate key="{marker.value}">{marker.value}</f:translate> - </f:else> - </f:if> - </td> - <td> - <f:if condition="{marker.usage}"> - <f:then> - {marker.usage} - </f:then> - <f:else> - <![CDATA[{]]>{marker.marker}<![CDATA[}]]> - </f:else> - </f:if> - </td> - <td> - <f:translate key="{marker.description}">{marker.description}</f:translate> - </td> - </tr> - </f:for> - </table> - </div> - <f:form class="col-md-12" method="post" controller="Mail" action="sendTestMail"> - <f:form.submit class="btn-primary btn form-group" value="{f:translate(key:'backend.send_test')}" /> - <f:form.textfield name="emailAddress" type="email" required="TRUE" class="email-input form-group" placeholder="{f:translate(key:'backend.email')}" /> - <f:form.hidden name="selectedLanguageLeft" value="{selectedLanguageLeft}" /> - <f:form.hidden name="selectedLanguageRight" value="{selectedLanguageRight}" /> - <f:form.hidden name="selectedTemplate" value="{selectedTemplateKey}" /> - <f:form.hidden name="selectedExtensionKey" value="{selectedTemplate.extension}" /> - <f:form.hidden name="selectedExtension" value="{selectedTemplate.extension}" /> - <f:form.hidden name="selectedTemplateKey" value="{selectedTemplateKey}" /> - </f:form> - <f:form method="post" controller="Mail" action="save"> - <div class="col-md-12 form-group"> - <f:form.submit class="btn-save-backend btn-success btn col-md-2 form-group" value="{f:translate(key:'backend.save')}" /> + <div class="row form-group col-md-12"> + <div class=" col-md-10"> + <p>{templateDescription}</p> </div> - <div class="col-md-6"> - <div class="form-group"> - <label class="">{f:translate(key:'backend.select_language')}</label> - <f:be.menus.actionMenu> - <f:for each="{languages}" as="language"> - <sgm:extendedIf condition="{language} == {selectedLanguageLeft}"> - <f:then> - <sgm:be.menus.actionMenuItem label="{language}" - controller="Mail" - action="index" - arguments="{selectedLanguageLeft: language, selectedLanguageRight: selectedLanguageRight, selectedTemplate: selectedTemplateKey, selectedExtensionKey: selectedTemplate.extension, selectedExtension: selectedTemplate.extension, selectedTemplateKey: selectedTemplateKey}" - additionalAttributes="{selected: 'selected'}" /> - </f:then> - <f:else> - <sgm:be.menus.actionMenuItem label="{language}" - controller="Mail" - action="index" - arguments="{selectedLanguageLeft: language, selectedLanguageRight: selectedLanguageRight, selectedTemplate: selectedTemplateKey, selectedExtensionKey: selectedTemplate.extension, selectedExtension: selectedTemplate.extension, selectedTemplateKey: selectedTemplateKey}" /> - </f:else> - </sgm:extendedIf> - </f:for> - </f:be.menus.actionMenu> - </div> - <div class="form-group"> - <f:link.action class="reset-btn btn-danger btn form-group" action="reset" arguments="{template: selectedTemplateKey, language: selectedLanguageLeft, extensionKey: selectedTemplate.extension}">{f:translate(key:'backend.button_reset')}</f:link.action> - </div> - <div class="form-group"> - <label for="fromNameLeft" class="">{f:translate(key:'backend.fromName')}</label> - <f:form.textfield type="text" class="form-control" value="{fromNameLeft}" name="fromNameLeft" /> - </div> - <div class="form-group"> - <label for="fromMailLeft" class="">{f:translate(key:'backend.fromMail')}</label> - <f:form.textfield type="email" class="form-control" value="{fromMailLeft}" name="fromMailLeft" /> - </div> - <div class="form-group"> - <label for="ccLeft" class="">{f:translate(key:'backend.cc')}</label> - <f:form.textfield type="text" class="form-control" value="{ccLeft}" name="ccLeft" /> - </div> - <div class="form-group"> - <label for="bccLeft" class="">{f:translate(key:'backend.bcc')}</label> - <f:form.textfield type="text" class="form-control" value="{bccLeft}" name="bccLeft" /> - </div> - <div class="form-group"> - <label for="replyToLeft" class="">{f:translate(key:'backend.replyTo')}</label> - <f:form.textfield type="text" class="form-control" value="{replyToLeft}" name="replyToLeft" /> - </div> - <div class="form-group"> - <label for="subjectLeft" class="">{f:translate(key:'backend.subject')}</label> - <f:form.textfield type="text" class="form-control" value="{subjectLeft}" name="subjectLeft" /> - </div> - <label for="contentLeft" class="">{f:translate(key:'backend.content')}</label> - <f:form.textarea class="form-control" rows="25" name="contentLeft" value="{contentLeft}" /> - <f:form.hidden name="selectedLanguageLeft" value="{selectedLanguageLeft}" /> - <f:form.hidden name="selectedLanguageRight" value="{selectedLanguageRight}" /> - <f:form.hidden name="selectedTemplate" value="{selectedTemplateKey}" /> - <f:form.hidden name="selectedExtensionKey" value="{selectedTemplate.extension}" /> - <f:form.hidden name="selectedExtension" value="{selectedTemplate.extension}" /> - <f:form.hidden name="selectedTemplateKey" value="{selectedTemplateKey}" /> + <div class=" col-md-2"> + <f:link.action class="reset-btn reset-all-btn btn-danger btn" style="width: 100%;" action="reset" arguments="{template: selectedTemplateKey, extensionKey: selectedTemplate.extension}">{f:translate(key:'backend.button_reset_all')}</f:link.action> </div> - - <div class="col-md-6"> - <div class="form-group"> - <label class="">{f:translate(key:'backend.select_language')}</label> - <f:be.menus.actionMenu> - <f:for each="{languages}" as="language"> - <sgm:extendedIf condition="{language} == {selectedLanguageRight}"> - <f:then> - <sgm:be.menus.actionMenuItem label="{language}" - controller="Mail" - action="index" - arguments="{selectedLanguageLeft: selectedLanguageLeft, selectedLanguageRight: language, selectedTemplate: selectedTemplateKey, selectedExtensionKey: selectedTemplate.extension, selectedExtension: selectedTemplate.extension, selectedTemplateKey: selectedTemplateKey}" - additionalAttributes="{selected: 'selected'}" /> - </f:then> - <f:else> - <sgm:be.menus.actionMenuItem label="{language}" - controller="Mail" - action="index" - arguments="{selectedLanguageLeft: selectedLanguageLeft, selectedLanguageRight: language, selectedTemplate: selectedTemplateKey, selectedExtensionKey: selectedTemplate.extension, selectedExtension: selectedTemplate.extension, selectedTemplateKey: selectedTemplateKey}" /> - </f:else> - </sgm:extendedIf> + </div> + <div class="col-md-12 row"> + <div class="col-md-12"> + <div class="form-group"> + <table class="table table-hover"> + <thead> + <tr> + <th><f:translate key="backend.marker" /></th> + <th><f:translate key="backend.type" /></th> + <th><f:translate key="backend.value" /></th> + <th><f:translate key="backend.usage" /></th> + <th><f:translate key="backend.description" /></th> + </tr> + </thead> + <f:for each="{selectedTemplate.marker}" as="marker"> + <tr> + <td>{marker.marker}</td> + <td> + <f:if condition="{marker.type}"> + <f:then> + <f:translate key="{marker.type}">{marker.type}</f:translate> + </f:then> + <f:else> + <f:translate key="backend.marker.type.string" /> + </f:else> + </f:if> + </td> + <td> + <f:if condition="{sgm:isArray(value: '{marker.value}')}"> + <f:then> + <f:for each="{marker.value}" as="value" key="key"> + {key}: {value} + <br /> + </f:for> + </f:then> + <f:else> + <f:translate key="{marker.value}">{marker.value}</f:translate> + </f:else> + </f:if> + </td> + <td> + <f:if condition="{marker.usage}"> + <f:then> + {marker.usage} + </f:then> + <f:else> + <![CDATA[{]]>{marker.marker}<![CDATA[}]]> + </f:else> + </f:if> + </td> + <td> + <f:translate key="{marker.description}">{marker.description}</f:translate> + </td> + </tr> </f:for> - </f:be.menus.actionMenu> + </table> </div> - <div class="form-group"> - <f:link.action class="reset-btn btn-danger btn form-group" action="reset" arguments="{template: selectedTemplateKey, language: selectedLanguageRight, extensionKey: selectedTemplate.extension}">{f:translate(key:'backend.button_reset')}</f:link.action> - </div> - <div class="form-group"> - <label for="fromNameRight" class="">{f:translate(key:'backend.fromName')}</label> - <f:form.textfield type="text" class="form-control" value="{fromNameRight}" name="fromNameRight" /> - </div> - <div class="form-group"> - <label for="fromMailRight" class="">{f:translate(key:'backend.fromMail')}</label> - <f:form.textfield type="email" class="form-control" value="{fromMailRight}" name="fromMailRight" /> - </div> - <div class="form-group"> - <label for="ccRight" class="">{f:translate(key:'backend.cc')}</label> - <f:form.textfield type="text" class="form-control" value="{ccRight}" name="ccRight" /> - </div> - <div class="form-group"> - <label for="bccRight" class="">{f:translate(key:'backend.bcc')}</label> - <f:form.textfield type="text" class="form-control" value="{bccRight}" name="bccRight" /> - </div> - <div class="form-group"> - <label for="replyToRight" class="">{f:translate(key:'backend.replyTo')}</label> - <f:form.textfield type="text" class="form-control" value="{replyToRight}" name="replyToRight" /> - </div> - <div class="form-group"> - <label for="subjectRight" class="">{f:translate(key:'backend.subject')}</label> - <f:form.textfield type="text" class=" form-control" value="{subjectRight}" name="subjectRight" /> - </div> - <label for="contentRight" class="">{f:translate(key:'backend.content')}</label> - <f:form.textarea class="form-control" rows="25" name="contentRight" value="{contentRight}" /> </div> - <div class="col-md-2"> - <div class="form-group"> - <f:form.submit class="btn-save-backend btn-success btn form-control" value="{f:translate(key:'backend.save')}" /> - </div> - </div> - </f:form> + </div> + <div class="row col-md-12 form-group"> + <f:form method="post" controller="Mail" action="sendTestMail"> + <div class="col-md-12 form-group"> + <f:form.submit class="btn-primary btn form-group" value="{f:translate(key:'backend.send_test')}" /> + <f:form.textfield name="parameters[emailAddress]" class="email-input form-group" value="{beUserMail}" /> + <f:form.hidden name="parameters[selectedTemplate]" value="{selectedTemplateKey}" /> + <f:form.hidden name="parameters[selectedExtensionKey]" value="{selectedTemplate.extension}" /> + <f:form.hidden name="parameters[selectedExtension]" value="{selectedTemplate.extension}" /> + <f:form.hidden name="parameters[selectedTemplateKey]" value="{selectedTemplateKey}" /> + </div> + <f:for each="{languageTemplates}" as="languageTemplate" key="key"> + <div class="template-col col-md-{colspace}"> + <f:for each="{languageLabels}" as="label" key="innerKey"> + <f:if condition="{key} == {innerKey}"> + <h3> + <f:if condition="{key}=='default'"> + <f:then> + {defaultLanguageLabel} + </f:then> + <f:else> + {label} + </f:else> + </f:if> + <f:if condition="{languageTemplate.isOverwritten}"> + <f:translate key="backend.is_overwritten" /> + </f:if> + </h3> + </f:if> + </f:for> + + <div class="col-md-12"> + <div class="row form-group"> + <label for="parameters[templates][{key}][fromName]" class="">{f:translate(key:'backend.fromName')}</label> + <f:form.textfield type="text" class="form-control" value="{languageTemplate.fromName}" name="parameters[templates][{key}][fromName]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][fromMail]" class="">{f:translate(key:'backend.fromMail')}</label> + <f:form.textfield type="email" class="form-control" value="{languageTemplate.fromMail}" name="parameters[templates][{key}][fromMail]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][toAddress]" class="">{f:translate(key:'backend.to_form')}</label> + <f:form.textfield type="text" class="form-control" value="{languageTemplate.toAddress}" name="parameters[templates][{key}][toAddress]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][cc]" class="">{f:translate(key:'backend.cc')}</label> + <f:form.textfield type="text" class="form-control" value="{languageTemplate.cc}" name="parameters[templates][{key}][cc]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][bcc]" class="">{f:translate(key:'backend.bcc')}</label> + <f:form.textfield type="text" class="form-control" value="{languageTemplate.bcc}" name="parameters[templates][{key}][bcc]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][replyTo]" class="">{f:translate(key:'backend.replyTo')}</label> + <f:form.textfield type="text" class="form-control" value="{languageTemplate.replyTo}" name="parameters[templates][{key}][replyTo]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][subject]" class="">{f:translate(key:'backend.subject')}</label> + <f:form.textfield type="text" class="form-control" value="{languageTemplate.subject}" name="parameters[templates][{key}][subject]" /> + </div> + <div class="row form-group"> + <label for="parameters[templates][{key}][content]" class="">{f:translate(key:'backend.content')}</label> + <f:form.textarea class="form-control" rows="15" name="parameters[templates][{key}][content]" value="{languageTemplate.content}" /> + </div> + </div> + </div> + </f:for> + </f:form> + </div> </f:then> <f:else> <f:render partial="Mail/Empty" /> </f:else> </f:if> + <f:if condition="{pages}"> + <div class="row"> + <div class="panel panel-default recordlist"> + <div class="table-fit"> + <table data-table="pages" class="table table-striped table-hover"> + <tbody> + <f:for each="{pages}" as="page"> + <tr data-uid="{page.pid}"> + <td nowrap="nowrap" class="col-title"> + <a href="#" onclick="sgMailGoToPage({page.uid}); return false;"> + <sgm:backend.icon table="pages" row="{page}" clickMenu="0" /> + {page._thePathFull} + </a> + </td> + </tr> + </f:for> + </tbody> + </table> + </div> + </div> + </div> + </f:if> </f:section> diff --git a/Resources/Private/Templates/Queue/Index.html b/Resources/Private/Templates/Queue/Index.html index bf640bfa217969bbc54200ab9db1d1e2bf1fa323..41ed367e40ed24bb3d2c4d0b461d78f35b57cc00 100644 --- a/Resources/Private/Templates/Queue/Index.html +++ b/Resources/Private/Templates/Queue/Index.html @@ -1,18 +1,32 @@ {namespace sgm=SGalinski\SgMail\ViewHelpers} - -<f:layout name="Default" /> +<f:layout name="Queue" /> <f:section name="iconButtons"> </f:section> <f:section name="content"> - <f:flashMessages/> + <f:flashMessages /> + <f:render partial="Queue/Filter" arguments="{filterFields: filterFields, filters: filters, languages: languages, templatesFilter: templatesFilter, selectedTemplateFilter: selectedTemplateFilter, selectedExtensionFilter: selectedExtensionFilter}" /> + <f:if condition="{queue -> f:count()} > 0"> <f:then> <div class="panel panel-default recordlist"> <div class="table-fit"> <table data-table="tx_sgmail_domain_model_mail" class="table table-striped table-hover"> <sgm:backend.widget.paginate objects="{queue}" as="paginatedMails" configuration="{insertAbove: 1, itemsPerPage: 20}"> + <thead> + <tr> + <th></th> + <th><f:translate key="backend.from" /> <br> <f:translate key="backend.to" /></th> + <th><f:translate key="backend.filter.extension" />: + <f:translate key="backend.filter.template" /> <br> + <f:translate key="backend.subject" /></th> + <th><f:translate key="backend.entry_date" /> <br> + <f:translate key="backend.last_sent" /></th> + <th></th> + <th></th> + </tr> + </thead> <tbody> <f:for each="{paginatedMails}" as="mail"> {sgm:backend.editOnClick(table: 'tx_sgmail_domain_model_mail', uid: mail.uid) -> sgm:set(name: 'editOnClick') -> f:format.raw()} @@ -22,69 +36,75 @@ <sgm:backend.icon table="tx_sgmail_domain_model_mail" row="{mail}" /> </f:format.raw> </td> - <td nowrap="nowrap"> - <a href="#" onclick="{editOnClick}"> - <span>{mail.from_address} -> {mail.to_address}, {mail.mail_subject}</span> - </a> + <td> + <span>{mail.from_address}</span> + <hr> + <span>{mail.to_address}</span> </td> - <td nowrap="nowrap" class="col-control"> - <f:format.raw> - <sgm:backend.control table="tx_sgmail_domain_model_mail" row="{mail}" /> - </f:format.raw> + <td> + <span>{mail.extension_key}: {mail.template_name}</span> + <hr> + <f:if condition="{mail.mail_subject}"> + <f:then> + <span><f:format.crop maxCharacters="40" append="...">{mail.mail_subject}</f:format.crop></span> + </f:then> + <f:else> + + </f:else> + </f:if> + </td> <td> - <f:if condition="{mail.sent} == '0'"> + <span><f:format.date format="d.m.Y H:i">{mail.crdate}</f:format.date></span> + <hr> + <f:if condition="{mail.last_sending_time} != 0"> <f:then> - <f:link.action class="btn btn-default btn-send-now" controller="Queue" action="sendMail" arguments="{uid: mail.uid}"> - <span class="t3js-icon icon icon-size-small icon-state-default actions-document-import-t3d"> - <span class="icon-markup"> - <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-document-import-t3d.svg" width="16" height="16"> - </span> - </span> - Send Now - </f:link.action> + <span><f:format.date format="d.m.Y H:i">{mail.last_sending_time}</f:format.date></span> </f:then> <f:else> - <f:link.action class="btn btn-default btn-resend" controller="Queue" action="sendMail" arguments="{uid: mail.uid}"> - <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-insert-reference"> - <span class="icon-markup"> - <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-insert-reference.svg" width="16" height="16"> - </span> - </span> - Send Again - </f:link.action> + <f:translate key="backend.not_sent" /> </f:else> </f:if> </td> + <td nowrap="nowrap" class="col-control"> + <f:format.raw> + <sgm:backend.control table="tx_sgmail_domain_model_mail" row="{mail}" /> + </f:format.raw> + </td> <td> + <f:link.action class="btn btn-default btn-send-now" controller="Queue" action="sendMail" arguments="{uid: mail.uid, selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey}"> + <span class="t3js-icon icon icon-size-small icon-state-default actions-document-import-t3d"> + <span class="icon-markup"> + <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-document-import-t3d.svg" width="16" height="16"> + </span> + </span> + <f:translate key="backend.send_now" /> + </f:link.action> <a class="btn btn-default btn-toggle" data-uid="{mail.uid}"> - <span class="t3js-icon icon icon-size-small icon-state-default actions-document-view"> - <span class="icon-markup"> - <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-document-view.svg" width="16" height="16"> - </span> + <span class="t3js-icon icon icon-size-small icon-state-default actions-document-view"> + <span class="icon-markup"> + <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-document-view.svg" width="16" height="16"> </span> + </span> <f:translate key="backend.showBody" /> </a> </td> - </tr><!-- Modal --> - <div class="modal fade" id="toggle-{mail.uid}" tabindex="-1" role="dialog" aria-labelledby="login-modal-label"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span></button> - <h4 class="modal-title" id="login-modal-label">{mail.mail_subject}</h4> - </div> - <div class="modal-body" id="login-modal-body"> - <div class="modalcol modalcol-left"> - <f:format.html> - {mail.mail_body} - </f:format.html> + <div class="modal fade" id="toggle-{mail.uid}" tabindex="-1" role="dialog" aria-labelledby="login-modal-label"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="login-modal-label">{mail.mail_subject}</h4> + </div> + <div class="modal-body" id="login-modal-body"> + <div class="modalcol modalcol-left"> + <f:format.html>{mail.mail_body}</f:format.html> + </div> </div> </div> </div> </div> - </div> </f:for> </tbody> </sgm:backend.widget.paginate> @@ -96,4 +116,24 @@ <f:render partial="Queue/Empty" /> </f:else> </f:if> + <f:if condition="{pages}"> + <div class="panel panel-default recordlist"> + <div class="table-fit"> + <table data-table="pages" class="table table-striped table-hover"> + <tbody> + <f:for each="{pages}" as="page"> + <tr data-uid="{page.pid}"> + <td nowrap="nowrap" class="col-title"> + <a href="#" onclick="sgMailGoToPage({page.uid}); return false;"> + <sgm:backend.icon table="pages" row="{page}" clickMenu="0" /> + {page._thePathFull} + </a> + </td> + </tr> + </f:for> + </tbody> + </table> + </div> + </div> + </f:if> </f:section> diff --git a/Resources/Private/Templates/ViewHelpers/Backend/Widget/Paginate/Index.html b/Resources/Private/Templates/ViewHelpers/Backend/Widget/Paginate/Index.html index 50dfbed4df2cfcbe9e8ff0546c3fd81cc7df51e5..8e912b4338dbe8ff97f10e86de4e9956c0012077 100644 --- a/Resources/Private/Templates/ViewHelpers/Backend/Widget/Paginate/Index.html +++ b/Resources/Private/Templates/ViewHelpers/Backend/Widget/Paginate/Index.html @@ -4,7 +4,7 @@ <f:if condition="{configuration.insertAbove}"> <thead> <tr> - <td colspan="6"> + <td colspan="10"> <f:render section="paginator" arguments="{pagination: pagination, position:'top', recordsLabel: configuration.recordsLabel}" /> </td> </tr> @@ -16,7 +16,7 @@ <f:if condition="{configuration.insertBelow}"> <tfoot> <tr> - <td colspan="6"> + <td colspan="10"> <f:render section="paginator" arguments="{pagination: pagination, position:'bottom', recordsLabel: configuration.recordsLabel}" /> </td> </tr> diff --git a/Resources/Public/Scripts/Backend.js b/Resources/Public/Scripts/Backend.js index 3c939d5fcbd59a217a7d2fd8060c36c36432f018..ae946a80097b5fcd3ecb5f63aa0c88bfcb356d6c 100644 --- a/Resources/Public/Scripts/Backend.js +++ b/Resources/Public/Scripts/Backend.js @@ -28,7 +28,7 @@ function toggleMailBody(_event) { var uid = $(_event.currentTarget).data('uid'); - $('#toggle-' + uid).detach().appendTo('body').modal('show');; + $('#toggle-' + uid).detach().appendTo('body').modal('show'); } $(document).ready(function() { @@ -36,6 +36,18 @@ $('.btn-send-now').on('click', sendMailListener); $('.btn-resend').on('click', resendMailListener); $('.btn-toggle').on('click', toggleMailBody); + $('#filter-reset-btn').on('click', function(event) { + event.preventDefault(); + this.form.reset(); + $(this).closest('form').find('select').each(function() { + this.selectedIndex = 0; + }); + + $('.reset-me').val(''); + $('#filters-all').attr('checked', true); + + this.form.submit(); + }); }); }) (TYPO3.jQuery); @@ -71,7 +83,7 @@ function setHighlight(id) { // * @param {number} uid */ function sgMailGoToPage(uid) { - top.nav.invokePageId(uid,gotToPageCallback); + top.nav.invokePageId(uid, gotToPageCallback); } /** @@ -79,7 +91,7 @@ function sgMailGoToPage(uid) { * * @param {number} uid */ -function gotToPageCallback(path){ +function gotToPageCallback(path) { var callback = top.Ext.createDelegate(top.nav.mainTree.selectPath, top.nav.mainTree); callback.apply(this, arguments); var node = top.nav.getSelected(); diff --git a/Resources/Public/StyleSheets/backend.css b/Resources/Public/StyleSheets/backend.css index 4282910f2c653356103686abc573414d4dc7e70e..cd2d7c1587000fb46173348afa91fabb85194645 100644 --- a/Resources/Public/StyleSheets/backend.css +++ b/Resources/Public/StyleSheets/backend.css @@ -15,8 +15,8 @@ .f3-widget-paginator { display: inline-block; border-radius: 4px; - margin: 20px 0px; - padding-left: 0px; + margin: 20px 0; + padding-left: 0; background-color: red; } @@ -45,7 +45,7 @@ .f3-widget-paginator > li:first-child > a, .f3-widget-paginator > li.current:first-child { - margin-left: 0px; + margin-left: 0; border-top-left-radius: 4px; border-bottom-left-radius: 4px; } @@ -54,4 +54,29 @@ .f3-widget-paginator > li.current:last-child { border-top-right-radius: 4px; border-bottom-right-radius: 4px; +} + +.template-col:nth-of-type(even) { + /*background-color: #DCDCDC;*/ + /*background-clip: content-box;*/ +} + +.template-col:nth-of-type(odd) { + /*background-color: #AAA;*/ + /*background-clip: content-box;*/ +} + +.recordlist hr { + margin: 5px 0; + border-top: 1px solid #EAEAEA; +} + +.recordlist-mail-unsent { + background-color: #CCC !important; +} + +.filter-btn { + width: auto; + min-width: 100px; + margin-right: 10px; } \ No newline at end of file diff --git a/ext_localconf.php b/ext_localconf.php index 0c0d4ff455c941f0854926a1bfdf883ff7a69deb..94cef014828ee608dc90ac9eb334a53c2c38c009 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -36,10 +36,25 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = \SGalinski\SgMail\Command\SendMailCommandController::class; // add upgrade wizard for moving all db entries to their respected siteroot -$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tx_sgmail_migrate_data'] = \SGalinski\SgMail\Updates\MigrateData::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tx_sgmail_update_pid_to_site_root'] = \SGalinski\SgMail\Updates\UpdatePidToSiteRoot::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tx_sgmail_update_sending_times'] = \SGalinski\SgMail\Updates\UpdateSendingTimes::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tx_sgmail_update_languages'] = \SGalinski\SgMail\Updates\UpdateLanguages::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tx_sgmail_update_german_as_default'] = \SGalinski\SgMail\Updates\UpdateGermanAsDefault::class; if (TYPO3_MODE === 'BE') { $tsPath = $extPath . 'Configuration/TypoScript/'; \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScriptSetup(file_get_contents($tsPath . 'setup.ts')); } + +// Cache registration +$cacheName = \SGalinski\SgMail\Service\MailTemplateService::CACHE_NAME; +if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheName])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheName] = []; +} +if (!isset($TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations'][$cacheName]['groups'])) { + $TYPO3_CONF_VARS['SYS']['caching']['cacheConfigurations'][$cacheName]['groups'] = [ + 'citypower' + ]; +} + diff --git a/ext_tables.php b/ext_tables.php index afd1c9f4419d2bc76b978032602151632390646d..13e821a25fd190684f0ae60d8b2e227f13d6c06f 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -10,8 +10,8 @@ if (!defined('TYPO3_MODE')) { 'Mail', '', [ - 'Mail' => 'index, save, sendTestMail, empty, reset', - 'Queue' => 'index, sendMail', + 'Mail' => 'index, sendTestMail, empty, reset', + 'Queue' => 'index, sendMail, export', ], [ 'access' => 'user,group', diff --git a/ext_tables.sql b/ext_tables.sql index a22cf39508fa23c7db2ee742e6460a2a9e52f572..e56a5c475b33e19fb5d603a390249566147bf72c 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -9,13 +9,13 @@ CREATE TABLE tx_sgmail_domain_model_mail ( from_name varchar(255) DEFAULT '' NOT NULL, cc_addresses varchar(255) DEFAULT '' NOT NULL, bcc_addresses varchar(255) DEFAULT '' NOT NULL, - sent tinyint(1) DEFAULT '0' NOT NULL, priority int(11) unsigned DEFAULT '0' NOT NULL, - extension_key varchar(30) DEFAULT '' NOT NULL, - template_name varchar(30) DEFAULT '' NOT NULL, - reply_to varchar(30) DEFAULT '' NOT NULL, + extension_key varchar(255) DEFAULT '' NOT NULL, + template_name varchar(255) DEFAULT '' NOT NULL, + reply_to varchar(255) DEFAULT '' NOT NULL, sending_time int(11) unsigned DEFAULT '0' NOT NULL, - site_root_id int(11) unsigned DEFAULT '0' NOT NULL, + last_sending_time int(11) unsigned DEFAULT '0' NOT NULL, + language varchar(255) DEFAULT '' NOT NULL, tstamp int(11) unsigned DEFAULT '0' NOT NULL, crdate int(11) unsigned DEFAULT '0' NOT NULL, @@ -33,12 +33,12 @@ CREATE TABLE tx_sgmail_domain_model_template ( uid int(11) NOT NULL auto_increment, pid int(11) DEFAULT '0' NOT NULL, - site_root_id int(11) unsigned DEFAULT '0' NOT NULL, subject text NOT NULL, extension_key varchar(255) DEFAULT '' NOT NULL, template_name varchar(255) DEFAULT '' NOT NULL, from_name varchar(255) DEFAULT '' NOT NULL, from_mail varchar(255) DEFAULT '' NOT NULL, + to_address varchar(255) DEFAULT '' NOT NULL, cc varchar(255) DEFAULT '' NOT NULL, bcc varchar(255) DEFAULT '' NOT NULL, reply_to varchar(255) DEFAULT '' NOT NULL,