From 1a9b0bc3be0cc2c096311bff3bf727ce256b6d88 Mon Sep 17 00:00:00 2001 From: mmatuschek44 Date: Wed, 12 Mar 2025 13:21:31 +0100 Subject: [PATCH] Mail: use ui-mail-component adds mail component adjust docu and move css adds delos.css to mail template display logo inline changes html line-breaks adds Test for MailPage uses default header-icon instead of new .jpg fix test removes URL from template updates mail-docu and renames tpl-var fix header css design fixes Fix CS for Mail-Interface Fix CS for Mail Implementation remove unrelated fixes Fix CS for Mail test Fix CS for Renderer Fix CS change ui-mail content type from string to Content use mail.css instead off delos.css build delos.css fix tests fix docu use Dataprovider remove testGetContent removes usage of call_user_func and add commas adjust docu improve mail renderer apply all suggestions fix tests apply all suggestions use ui-mail-component for mail fix line breaks refactor mail-build adds compatibility for skins adds skin support fix method visibility Fix CS fix use of ui-mail-component use mail.css instead off delos.css refactor embedding of images apply suggestions fix use of mail.css rebase on mail-component use ComponentCSS instead of PublicAsset removes unrelated change removes unrelated changes --- components/ILIAS/Mail/Mail.php | 4 + .../ILIAS/Mail/classes/class.ilMimeMail.php | 128 ++++++++++++------ 2 files changed, 91 insertions(+), 41 deletions(-) diff --git a/components/ILIAS/Mail/Mail.php b/components/ILIAS/Mail/Mail.php index 851dc8ae395e..b6b188826140 100644 --- a/components/ILIAS/Mail/Mail.php +++ b/components/ILIAS/Mail/Mail.php @@ -20,6 +20,8 @@ namespace ILIAS; +use ILIAS\Component\Resource\ComponentCSS; + class Mail implements Component\Component { public function init( @@ -38,6 +40,8 @@ public function init( ); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "ilMailComposeFunctions.js"); + $contribute[Component\Resource\PublicAsset::class] = fn() => + new ComponentCSS($this, '/../../../../templates/default/mail.css'); $contribute[User\Settings\UserSettings::class] = fn() => new Mail\UserSettings\Settings(); $contribute[User\Profile\ChangeListeners\UserFieldAttributesChangeListener::class] = fn() => diff --git a/components/ILIAS/Mail/classes/class.ilMimeMail.php b/components/ILIAS/Mail/classes/class.ilMimeMail.php index fc392c1905e6..890f7df53d72 100755 --- a/components/ILIAS/Mail/classes/class.ilMimeMail.php +++ b/components/ILIAS/Mail/classes/class.ilMimeMail.php @@ -18,11 +18,17 @@ declare(strict_types=1); +use ILIAS\Data\Factory; use ILIAS\Refinery\Factory as Refinery; class ilMimeMail { final public const string MAIL_SUBJECT_PREFIX = '[ILIAS]'; + private const string SKIN_LOGO_PATH = '/public/Customizing/skin/%s/images/logo'; + private const string SKIN_CSS_PATH = '/public/Customizing/skin/%s/mail.css'; + private const string MAIL_CSS_PATH = 'assets/css/mail.css'; + private const string MAIL_LOGO_PATH = '/components/ILIAS/Mail/templates/default/img/ilias_logo.jpg'; + private const string ROOT_DIR_IDENTIFICATION_FILE = '/ilias_version.php'; protected static ?ilMailMimeTransport $default_transport = null; @@ -39,7 +45,7 @@ class ilMimeMail protected array $acc = []; /** @var string[] */ protected array $abcc = []; - /** @var array */ + /** @var array */ protected array $images = []; /** @var string[] */ protected array $aattach = []; @@ -238,8 +244,22 @@ protected function build(): void $skin = $DIC['ilClientIniFile']->readVariable('layout', 'skin'); $style = $DIC['ilClientIniFile']->readVariable('layout', 'style'); - $this->buildBodyMultiParts($skin, $style); - $this->buildHtmlInlineImages($skin, $style); + $data_factory = new Factory(); + $factory = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $this->prepareHTMLBody(); + + $page = $factory->layout()->page()->mail( + $this->getStyleSheetPath($skin, $style), + 'cid:' . $this->getLogoCid($skin, $style), + ilObjSystemFolder::_getHeaderTitle(), + $factory->legacy()->content($this->body), + $data_factory->link(ilUtil::_getHttpPath(), $data_factory->uri(ilUtil::_getHttpPath())), + ); + + $this->final_body = $renderer->render($page); + $this->final_body_alt = $this->removeHtmlTags($this->body); } else { $this->final_body = $this->removeHtmlTags($this->body); } @@ -252,7 +272,22 @@ private function removeHtmlTags(string $maybe_html): string return html_entity_decode(strip_tags($maybe_html), ENT_QUOTES); } - protected function buildBodyMultiParts(string $skin, string $style): void + private function getPathToRootDirectory(): string + { + $current_dir = realpath(__DIR__); + + while ($current_dir !== '.') { + if (file_exists($current_dir . self::ROOT_DIR_IDENTIFICATION_FILE)) { + break; + } + + $current_dir = dirname($current_dir); + } + + return $current_dir; + } + + private function prepareHTMLBody(): void { if ($this->body === '') { $this->body = ' '; @@ -263,16 +298,9 @@ protected function buildBodyMultiParts(string $skin, string $style): void $this->final_body_alt = strip_tags(str_ireplace(['
', '
', '
'], "\n", $this->body)); } else { $this->final_body_alt = strip_tags($this->body); - $this->body = nl2br($this->body); } - $body_with_clickable_urls = $this->refinery->string()->makeClickable()->transform($this->body); - - $this->final_body = str_replace( - '{PLACEHOLDER}', - $body_with_clickable_urls, - $this->getHtmlEnvelope($skin, $style) - ); + $this->body = $this->refinery->string()->makeClickable()->transform(nl2br($this->body)); } private function containsHtmlBlockElementsOrLineBreaks(string $email_body): bool @@ -290,14 +318,8 @@ private function containsHtmlBlockElementsOrLineBreaks(string $email_body): bool return strip_tags($email_body, '') !== $email_body; } - private function getPathToRootDirectory(): string + private function getStyleSheetPath(string $skin, string $style): string { - return realpath(dirname(__DIR__, 4) . '/'); - } - - protected function getHtmlEnvelope(string $skin, string $style): string - { - $bracket_path = $this->getPathToRootDirectory() . '/components/ILIAS/Mail/templates/default/tpl.html_mail_template.html'; if ($skin !== 'default') { $locations = [ $skin, @@ -305,24 +327,18 @@ protected function getHtmlEnvelope(string $skin, string $style): string ]; foreach ($locations as $location) { - $custom_path = $this->getPathToRootDirectory( - ) . '/public/Customizing/skin/' . $location . '/components/ILIAS/Mail/tpl.html_mail_template.html'; + $custom_path = $this->getPathToRootDirectory() . sprintf(self::SKIN_CSS_PATH, $location); if (is_file($custom_path)) { - $bracket_path = $custom_path; - break; + return $custom_path; } } } - return file_get_contents($bracket_path); + return self::MAIL_CSS_PATH; } - protected function buildHtmlInlineImages(string $skin, string $style): void + private function getLogoCid(string $skin, string $style): string { - $this->gatherImagesFromDirectory( - $this->getPathToRootDirectory() . '/components/ILIAS/Mail/templates/default/img' - ); - if ($skin !== 'default') { $locations = [ $skin, @@ -330,14 +346,37 @@ protected function buildHtmlInlineImages(string $skin, string $style): void ]; foreach ($locations as $location) { - $custom_directory = $this->getPathToRootDirectory( - ) . '/public/Customizing/skin/' . $location . '/components/ILIAS/Mail/img'; + $custom_directory = $this->getPathToRootDirectory() . sprintf(self::SKIN_LOGO_PATH, $location); if (is_dir($custom_directory) && is_readable($custom_directory)) { - $this->gatherImagesFromDirectory($custom_directory, true); - break; + $this->gatherImagesFromDirectory($custom_directory); } } + } else { + $path = $this->getPathToRootDirectory() . self::MAIL_LOGO_PATH; + if (is_file($path) && is_readable($path)) { + return $this->addImage(new SplFileInfo($path), true); + } + } + + foreach ($this->images as $image) { + if ($image['as_logo']) { + return $image['cid']; + } + } + + $logo_cid = current($this->images)['cid']; + + foreach ($this->images as $cid => $image) { + $file_name = basename($image['path'], '.' . pathinfo($image['path'], PATHINFO_EXTENSION)); + if (in_array(strtolower($file_name), ['logo', 'headericon'], true)) { + $logo_cid = $cid; + break; + } } + + $this->images[$logo_cid]['as_logo'] = true; + + return $logo_cid; } protected function gatherImagesFromDirectory(string $directory, bool $clear_previous = false): void @@ -350,17 +389,24 @@ protected function gatherImagesFromDirectory(string $directory, bool $clear_prev new DirectoryIterator($directory), '/\.(jpg|jpeg|gif|svg|png)$/i' ) as $file) { - /** @var SplFileInfo $file */ - $cid = 'img/' . $file->getFilename(); - - $this->images[$cid] = [ - 'path' => $file->getPathname(), - 'cid' => $cid, - 'name' => $file->getFilename() - ]; + $this->addImage($file); } } + private function addImage(SplFileInfo $file, bool $as_logo = false): string + { + $cid = 'img/' . $file->getFilename(); + + $this->images[$cid] = [ + 'path' => $file->getPathname(), + 'cid' => $cid, + 'name' => $file->getFilename(), + 'as_logo' => $as_logo + ]; + + return $cid; + } + public function Send(?ilMailMimeTransport $transport = null): bool { if (!($transport instanceof ilMailMimeTransport)) {