diff --git a/src/Eccube/Controller/Admin/Order/MailController.php b/src/Eccube/Controller/Admin/Order/MailController.php index a126f2e5ae6..f45b03ccb41 100644 --- a/src/Eccube/Controller/Admin/Order/MailController.php +++ b/src/Eccube/Controller/Admin/Order/MailController.php @@ -194,8 +194,15 @@ public function index(Request $request, Order $Order) private function createBody($Order, $twig = 'Mail/order.twig') { - return $this->renderView($twig, [ - 'Order' => $Order, - ]); + $body = ''; + try { + $body = $this->renderView($twig, [ + 'Order' => $Order, + ]); + } catch (\Exception $e) { + log_warning($e->getMessage()); + } + + return $body; } } diff --git a/src/Eccube/Controller/Admin/Setting/Shop/MailController.php b/src/Eccube/Controller/Admin/Setting/Shop/MailController.php index 4abe761aeee..ad455ce1ab7 100644 --- a/src/Eccube/Controller/Admin/Setting/Shop/MailController.php +++ b/src/Eccube/Controller/Admin/Setting/Shop/MailController.php @@ -55,6 +55,7 @@ public function __construct(MailTemplateRepository $mailTemplateRepository) */ public function index(Request $request, Environment $twig, CacheUtil $cacheUtil, MailTemplate $Mail = null) { + $Mail = $Mail ?? new MailTemplate(); $builder = $this->formFactory ->createBuilder(MailType::class, $Mail); @@ -68,17 +69,20 @@ public function index(Request $request, Environment $twig, CacheUtil $cacheUtil, $this->eventDispatcher->dispatch($event, EccubeEvents::ADMIN_SETTING_SHOP_MAIL_INDEX_INITIALIZE); $form = $builder->getForm(); - $form['template']->setData($Mail); - $htmlFileName = $Mail ? $this->getHtmlFileName($Mail->getFileName()) : null; // 更新時 - if (!is_null($Mail)) { + if (null !== $Mail->getId()) { + $form['template']->setData($Mail); + // テンプレートファイルの取得 $source = $twig->getLoader() ->getSourceContext($Mail->getFileName()) ->getCode(); $form->get('tpl_data')->setData($source); + + $htmlFileName = $this->getHtmlFileName($Mail->getFileName()); + if ($twig->getLoader()->exists($htmlFileName)) { $source = $twig->getLoader() ->getSourceContext($htmlFileName) @@ -91,14 +95,9 @@ public function index(Request $request, Environment $twig, CacheUtil $cacheUtil, if ('POST' === $request->getMethod()) { $form->handleRequest($request); - // 新規登録は現時点では未実装とする. - if (is_null($Mail)) { - $this->addError('admin.common.save_error', 'admin'); - - return $this->redirectToRoute('admin_setting_shop_mail'); - } - - if ($form->isValid()) { + if ($form->isSubmitted() && $form->isValid()) { + $Mail = $form->getData(); + $this->entityManager->persist($Mail); $this->entityManager->flush(); // ファイル生成・更新 @@ -112,9 +111,17 @@ public function index(Request $request, Environment $twig, CacheUtil $cacheUtil, // HTMLファイル用 $htmlMailData = $form->get('html_tpl_data')->getData(); + $htmlFileName = $this->getHtmlFileName($Mail->getFileName()); + if (!is_null($htmlMailData)) { $htmlMailData = StringUtil::convertLineFeed($htmlMailData); $fs->dumpFile($templatePath.'/'.$htmlFileName, $htmlMailData); + } else { + // 空登録の場合は削除 + $htmlFilePath = $templatePath.'/'.$htmlFileName; + if ($this->validateFilePath($htmlFilePath) && is_file($htmlFilePath) ) { + $fs->remove($htmlFilePath); + } } $event = new EventArgs( @@ -139,7 +146,8 @@ public function index(Request $request, Environment $twig, CacheUtil $cacheUtil, return [ 'form' => $form->createView(), - 'id' => is_null($Mail) ? null : $Mail->getId(), + 'id' => $Mail->getId(), + 'Mail' => $Mail, ]; } @@ -168,6 +176,40 @@ public function preview(Request $request) ]; } + /** + * @Route("/%eccube_admin_route%/setting/shop/mail/{id}/delete", requirements={"id" = "\d+"}, name="admin_setting_shop_mail_delete", methods={"DELETE"}) + */ + public function delete(Request $request, MailTemplate $Mail) + { + $this->isTokenValid(); + + if (!$Mail->isDeletable()) { + return $this->redirectToRoute('admin_setting_shop_mail'); + } + + log_info('メールテンプレート削除開始', [$Mail->getId()]); + + $this->entityManager->remove($Mail); + $this->entityManager->flush(); + + $fs = new Filesystem(); + $templatePath = $this->getParameter('eccube_theme_front_dir'); + $filePath = $templatePath.'/'.$Mail->getFileName(); + if ($this->validateFilePath($filePath) && is_file($filePath)) { + $fs->remove($filePath); + } + $htmlFilePath = $templatePath.'/'.$this->getHtmlFileName($Mail->getFileName()); + if ($this->validateFilePath($htmlFilePath) && is_file($htmlFilePath)) { + $fs->remove($htmlFilePath); + } + + $this->addSuccess('admin.common.delete_complete', 'admin'); + + log_info('メールテンプレート削除完了', [$Mail->getId()]); + + return $this->redirectToRoute('admin_setting_shop_mail'); + } + /** * HTML用テンプレート名を取得する * @@ -183,4 +225,18 @@ protected function getHtmlFileName($fileName) return $targetTemplate['dirname'].DIRECTORY_SEPARATOR.$targetTemplate['filename'].$suffix.'.'.$targetTemplate['extension']; } + + /** + * テンプレートディレクトリ配下のパスかどうかを検証する + * + * @param $path + * @return bool + */ + protected function validateFilePath($path) + { + $templatePath = realpath($this->getParameter('eccube_theme_front_dir')); + $path = realpath($path); + + return \str_starts_with($path, $templatePath); + } } diff --git a/src/Eccube/Entity/MailTemplate.php b/src/Eccube/Entity/MailTemplate.php index 03155117a95..1fc6eb3fd2c 100644 --- a/src/Eccube/Entity/MailTemplate.php +++ b/src/Eccube/Entity/MailTemplate.php @@ -89,6 +89,15 @@ public function __toString() */ private $Creator; + /** + * テンプレートの削除可否。 + * + * @var bool + * + * @ORM\Column(name="deletable", type="boolean", options={"default":false})) + */ + private bool $deletable = false; + /** * Get id. * @@ -242,5 +251,25 @@ public function getCreator() { return $this->Creator; } + + + /** + * @return bool + */ + public function isDeletable(): bool + { + return $this->deletable; + } + + /** + * @param bool $deletable + * @return $this + */ + public function setDeletable(bool $deletable): self + { + $this->deletable = $deletable; + + return $this; + } } } diff --git a/src/Eccube/Form/Type/Admin/MailType.php b/src/Eccube/Form/Type/Admin/MailType.php index 58afcd295b5..454ddce8f2a 100644 --- a/src/Eccube/Form/Type/Admin/MailType.php +++ b/src/Eccube/Form/Type/Admin/MailType.php @@ -13,16 +13,33 @@ namespace Eccube\Form\Type\Admin; +use Eccube\Common\EccubeConfig; +use Eccube\Entity\MailTemplate; use Eccube\Form\Type\Master\MailTemplateType; use Eccube\Form\Validator\TwigLint; +use Eccube\Repository\MailTemplateRepository; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; +use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints as Assert; class MailType extends AbstractType { + private MailTemplateRepository $mailTemplateRepository; + + private EccubeConfig $eccubeConfig; + + public function __construct(MailTemplateRepository $mailTemplateRepository, EccubeConfig $eccubeConfig) + { + $this->mailTemplateRepository = $mailTemplateRepository; + $this->eccubeConfig = $eccubeConfig; + } + /** * {@inheritdoc} */ @@ -30,16 +47,20 @@ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('template', MailTemplateType::class, [ - 'required' => true, + 'required' => false, 'mapped' => false, + ]) + ->add('name', TextType::class, [ 'constraints' => [ new Assert\NotBlank(), + new Assert\Length(['max' => $this->eccubeConfig['eccube_stext_len']]), ], ]) ->add('mail_subject', TextType::class, [ 'required' => true, 'constraints' => [ new Assert\NotBlank(), + new Assert\Length(['max' => $this->eccubeConfig['eccube_stext_len']]), ], ]) ->add('tpl_data', TextareaType::class, [ @@ -59,6 +80,47 @@ public function buildForm(FormBuilderInterface $builder, array $options) ], ]) ; + + $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) { + $data = $event->getData(); + if (null === $data->getId()) { + $form = $event->getForm(); + $form->add('file_name', TextType::class, [ + 'constraints' => [ + new Assert\NotBlank(), + new Assert\Regex(['pattern' => '/^[0-9a-z_-]+$/']), + new Assert\Length(['max' => $this->eccubeConfig['eccube_stext_len']]), + ], + ]); + } + }); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { + $data = $event->getData(); + if (null === $data->getId()) { + $filename = 'Mail/'.$data->getFileName().'.twig'; + $MailTemplate = $this->mailTemplateRepository->findBy(['file_name' => $filename]); + if ($MailTemplate) { + $form = $event->getForm(); + $form['file_name']->addError(new FormError(trans('admin.setting.shop.mail.file_exists'))); + } else { + $data->setFileName('Mail/'.$data->getFileName().'.twig'); + } + + $data->setDeletable(true); + } + }); + + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => MailTemplate::class, + ]); } /** diff --git a/src/Eccube/Form/Type/Admin/OrderMailType.php b/src/Eccube/Form/Type/Admin/OrderMailType.php index c0d4a2e653d..2eacf4b9540 100644 --- a/src/Eccube/Form/Type/Admin/OrderMailType.php +++ b/src/Eccube/Form/Type/Admin/OrderMailType.php @@ -52,8 +52,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'mapped' => false, 'query_builder' => function (EntityRepository $er) { return $er->createQueryBuilder('mt') - ->andWhere('mt.id = :id') - ->setParameter('id', $this->eccubeConfig['eccube_order_mail_template_id']) ->orderBy('mt.id', 'ASC'); }, ]) diff --git a/src/Eccube/Resource/doctrine/import_csv/en/dtb_mail_template.csv b/src/Eccube/Resource/doctrine/import_csv/en/dtb_mail_template.csv index 361ac6db677..9d899a2ecca 100644 --- a/src/Eccube/Resource/doctrine/import_csv/en/dtb_mail_template.csv +++ b/src/Eccube/Resource/doctrine/import_csv/en/dtb_mail_template.csv @@ -1,10 +1,10 @@ -id,creator_id,name,file_name,mail_subject,create_date,update_date,discriminator_type -1,,Order Receipt,Mail/order.twig,Thank you for your order!,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -2,,Temporary Registration,Mail/entry_confirm.twig,Member registration confirmation,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -3,,Regular Registration,Mail/entry_complete.twig,Your registration has been completed,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -4,,Membership Cancelation,Mail/customer_withdraw_mail.twig,Membership cancelation completed,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -5,,Inquiry Receipt,Mail/contact_mail.twig,Thank you for your inqury,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -6,,Password Reset,Mail/forgot_mail.twig,Reset your password,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -7,,Password Reminder,Mail/reset_complete_mail.twig,Your password has been changed,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -8,,Shipping Notice,Mail/shipping_notify.twig,Your order has been shipped,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate -9,,Notification email,Mail/customer_change_notify.twig,Your account information has been changed.,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +id,creator_id,name,file_name,mail_subject,deletable,create_date,update_date,discriminator_type +1,,Order Receipt,Mail/order.twig,Thank you for your order!,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +2,,Temporary Registration,Mail/entry_confirm.twig,Member registration confirmation,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +3,,Regular Registration,Mail/entry_complete.twig,Your registration has been completed,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +4,,Membership Cancelation,Mail/customer_withdraw_mail.twig,Membership cancelation completed,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +5,,Inquiry Receipt,Mail/contact_mail.twig,Thank you for your inqury,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +6,,Password Reset,Mail/forgot_mail.twig,Reset your password,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +7,,Password Reminder,Mail/reset_complete_mail.twig,Your password has been changed,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +8,,Shipping Notice,Mail/shipping_notify.twig,Your order has been shipped,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate +9,,Notification email,Mail/customer_change_notify.twig,Your account information has been changed.,0,2017-03-07 10:14:52,2017-03-07 10:14:52,mailtemplate diff --git a/src/Eccube/Resource/doctrine/import_csv/ja/dtb_mail_template.csv b/src/Eccube/Resource/doctrine/import_csv/ja/dtb_mail_template.csv index bb80f881d8a..8c4591668ef 100644 --- a/src/Eccube/Resource/doctrine/import_csv/ja/dtb_mail_template.csv +++ b/src/Eccube/Resource/doctrine/import_csv/ja/dtb_mail_template.csv @@ -1,10 +1,10 @@ -id,creator_id,name,file_name,mail_subject,create_date,update_date,discriminator_type -"1",,"注文受付メール","Mail/order.twig","ご注文ありがとうございます","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"2",,"会員仮登録メール","Mail/entry_confirm.twig","会員登録のご確認","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"3",,"会員本登録メール","Mail/entry_complete.twig","会員登録が完了しました。","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"4",,"会員退会メール","Mail/customer_withdraw_mail.twig","退会手続きのご完了","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"5",,"問合受付メール","Mail/contact_mail.twig","お問い合わせを受け付けました。","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"6",,"パスワードリセット","Mail/forgot_mail.twig","パスワード変更のご確認","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"7",,"パスワードリマインダー","Mail/reset_complete_mail.twig","パスワード変更のお知らせ","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"8",,"出荷通知メール","Mail/shipping_notify.twig","商品出荷のお知らせ","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" -"9",,"会員情報変更通知メール","Mail/customer_change_notify.twig","会員情報変更のお知らせ","2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +id,creator_id,name,file_name,mail_subject,deletable,create_date,update_date,discriminator_type +"1",,"注文受付メール","Mail/order.twig","ご注文ありがとうございます",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"2",,"会員仮登録メール","Mail/entry_confirm.twig","会員登録のご確認",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"3",,"会員本登録メール","Mail/entry_complete.twig","会員登録が完了しました。",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"4",,"会員退会メール","Mail/customer_withdraw_mail.twig","退会手続きのご完了",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"5",,"問合受付メール","Mail/contact_mail.twig","お問い合わせを受け付けました。",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"6",,"パスワードリセット","Mail/forgot_mail.twig","パスワード変更のご確認",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"7",,"パスワードリマインダー","Mail/reset_complete_mail.twig","パスワード変更のお知らせ",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"8",,"出荷通知メール","Mail/shipping_notify.twig","商品出荷のお知らせ",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" +"9",,"会員情報変更通知メール","Mail/customer_change_notify.twig","会員情報変更のお知らせ",0,"2017-03-07 10:14:52","2017-03-07 10:14:52","mailtemplate" diff --git a/src/Eccube/Resource/locale/messages.en.yaml b/src/Eccube/Resource/locale/messages.en.yaml index 3814214df3c..01fa5bca2ce 100644 --- a/src/Eccube/Resource/locale/messages.en.yaml +++ b/src/Eccube/Resource/locale/messages.en.yaml @@ -1236,11 +1236,16 @@ admin.setting.shop.tax.apply_date.available_error: The same date and time cannot admin.setting.shop.mail.mail_template_edit: Edit Templates admin.setting.shop.mail.mail_template: Template +admin.setting.shop.mail.mail_template_name: Template name +admin.setting.shop.mail.mail_file_name: File name admin.setting.shop.mail.mail_subject: Title admin.setting.shop.mail.mail_body: Body admin.setting.shop.mail.mail_text: Text admin.setting.shop.mail.mail_html: HTML admin.setting.shop.mail.preview: Preview +admin.setting.shop.mail.file_exists: This file name is already in use. +admin.setting.shop.mail.delete__confirm_title: Delete a mail template +admin.setting.shop.mail.delete__confirm_message: Are you sure to delete this mail template? #------------------------------------------------------------------------------------ # Settings : Store Settings : CSV Outputs diff --git a/src/Eccube/Resource/locale/messages.ja.yaml b/src/Eccube/Resource/locale/messages.ja.yaml index dc25f2d14a5..9cf4b99c635 100644 --- a/src/Eccube/Resource/locale/messages.ja.yaml +++ b/src/Eccube/Resource/locale/messages.ja.yaml @@ -1236,11 +1236,16 @@ admin.setting.shop.tax.apply_date.available_error: 同時刻の適用日時を admin.setting.shop.mail.mail_template_edit: テンプレート編集 admin.setting.shop.mail.mail_template: テンプレート +admin.setting.shop.mail.mail_template_name: テンプレート名 +admin.setting.shop.mail.mail_file_name: ファイル名 admin.setting.shop.mail.mail_subject: 件名 admin.setting.shop.mail.mail_body: 本文 admin.setting.shop.mail.mail_text: テキスト admin.setting.shop.mail.mail_html: HTML admin.setting.shop.mail.preview: プレビュー +admin.setting.shop.mail.file_exists: このファイル名はすでに使用されています。 +admin.setting.shop.mail.delete__confirm_title: メールテンプレートを削除します。 +admin.setting.shop.mail.delete__confirm_message: メールテンプレートを削除してよろしいですか? #------------------------------------------------------------------------------------ # 設定:店舗設定:CSV出力項目設定 diff --git a/src/Eccube/Resource/template/admin/Setting/Shop/mail.twig b/src/Eccube/Resource/template/admin/Setting/Shop/mail.twig index 8b7745a115c..1f8c84d27a6 100644 --- a/src/Eccube/Resource/template/admin/Setting/Shop/mail.twig +++ b/src/Eccube/Resource/template/admin/Setting/Shop/mail.twig @@ -56,18 +56,16 @@ file that was distributed with this source code. showInvisibles: true }); - {% if form.html_tpl_data.vars.value %} - var html_editor = ace.edit('html_editor'); - html_editor.session.setMode('ace/mode/twig'); - html_editor.setTheme('ace/theme/tomorrow'); - html_editor.setValue("{{ form.html_tpl_data.vars.value|escape('js') }}"); - html_editor.setOptions({ - enableBasicAutocompletion: true, - enableSnippets: true, - enableLiveAutocompletion: true, - showInvisibles: true - }); - {% endif %} + var html_editor = ace.edit('html_editor'); + html_editor.session.setMode('ace/mode/twig'); + html_editor.setTheme('ace/theme/tomorrow'); + html_editor.setValue("{{ form.html_tpl_data.vars.value|escape('js') }}"); + html_editor.setOptions({ + enableBasicAutocompletion: true, + enableSnippets: true, + enableLiveAutocompletion: true, + showInvisibles: true + }); $("#editor").resizable({ resize: function (event, ui) { @@ -83,9 +81,7 @@ file that was distributed with this source code. $('#form1').on('submit', function() { $('#mail_tpl_data').val(editor.getValue()); - {% if form.html_tpl_data.vars.value %} - $('#mail_html_tpl_data').val(html_editor.getValue()); - {% endif %} + $('#mail_html_tpl_data').val(html_editor.getValue()); }); // HTMLメールモーダル表示 @@ -139,9 +135,43 @@ file that was distributed with this source code. {{ 'admin.setting.shop.mail.mail_template'|trans }} + {% if Mail.isDeletable %} +