From ec4a67c2968e85bdb7757e67a254b47cbe691242 Mon Sep 17 00:00:00 2001 From: "arash.poorakbar" <arash.poorakbar@pronovix.com> Date: Fri, 23 May 2025 10:42:23 +0200 Subject: [PATCH 01/21] Add file attachment submodule --- .../markdownify_file_attachment.info.yml | 8 ++ .../markdownify_file_attachment.module | 75 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 modules/file_attachment/markdownify_file_attachment.info.yml create mode 100644 modules/file_attachment/markdownify_file_attachment.module diff --git a/modules/file_attachment/markdownify_file_attachment.info.yml b/modules/file_attachment/markdownify_file_attachment.info.yml new file mode 100644 index 0000000..7ba81df --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.info.yml @@ -0,0 +1,8 @@ +name: Markdownify File Attachment +description: This module provides support for rendering files in the markdown. +package: AI +type: module +core_version_requirement: ^9 || ^10 || ^11 +dependencies: + - drupal:file + - markdownify:markdownify diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module new file mode 100644 index 0000000..9950801 --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -0,0 +1,75 @@ +<?php + +/** + * @file + * Main module file for Markdownify File Attachment. + */ + +declare(strict_types = 1); + +use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Field\FieldItemListInterface; +use Drupal\file\FileInterface; + +/** + * Implements hook_markdownify_entity_html_alter(). + */ +function markdownify_file_attachment_markdownify_entity_html_alter(string &$html, array $context): void { + $entity = $context['entity'] ?? NULL; + if (!$entity instanceof ContentEntityInterface) { + return; + } + + $output = ''; + $allowed_extensions = [ + 'txt', 'json', 'yaml', 'yml', 'wsdl', 'rst', 'csv', 'tsv', 'rtf', 'doc', 'xml', + ]; + $max_size = 1024 * 1024; + + foreach ($entity->getFields() as $field) { + // Skip fields that aren't referencing files. + if (!$field instanceof FieldItemListInterface || $field->isEmpty()) { + continue; + } + + $field_def = $field->getFieldDefinition(); + $target_type = $field_def->getFieldStorageDefinition()->getSetting('target_type') ?? NULL; + + if ($target_type !== 'file') { + continue; + } + + foreach ($field->referencedEntities() as $file) { + if (!$file instanceof FileInterface) { + continue; + } + + $uri = $file->getFileUri(); + $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); + $filename = $file->getFilename(); + $filesize = $file->getSize(); + $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + + if (in_array($extension, $allowed_extensions) && $filesize < $max_size) { + $real_path = \Drupal::service('file_system')->realpath($uri); + $content = @file_get_contents($real_path); + + $output .= <<<EOD + Attached file **{$filename}** with format **{$extension}** available at [{$url}] follows: \n + ```{$extension} + {$content} + ``` + EOD; + + } + else { + $output .= "\nAttached file {$filename} with format {$extension} is available at [$url]\n"; + } + } + } + + if ($output) { + $html .= "\n\n" . $output; + } + +} -- GitLab From 44c6706d9e171e71aa6f0bd6aea5f47fb4907064 Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <72541-arash.poorakbar@users.noreply.drupalcode.org> Date: Fri, 23 May 2025 09:16:14 +0000 Subject: [PATCH 02/21] Fix strict type syntax --- modules/file_attachment/markdownify_file_attachment.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 9950801..52727f7 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -5,7 +5,7 @@ * Main module file for Markdownify File Attachment. */ -declare(strict_types = 1); +declare(strict_types=1); use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Field\FieldItemListInterface; -- GitLab From d4b8d1516d9a40e77341d9bcb647ae174fbc7e8c Mon Sep 17 00:00:00 2001 From: "arash.poorakbar" <arash.poorakbar@gmail.com> Date: Tue, 27 May 2025 13:39:34 +0200 Subject: [PATCH 03/21] Add file access check --- .../file_attachment/markdownify_file_attachment.module | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 52727f7..4d140bc 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -8,7 +8,7 @@ declare(strict_types=1); use Drupal\Core\Entity\ContentEntityInterface; -use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\file\FileInterface; /** @@ -28,7 +28,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html foreach ($entity->getFields() as $field) { // Skip fields that aren't referencing files. - if (!$field instanceof FieldItemListInterface || $field->isEmpty()) { + if (!$field instanceof EntityReferenceFieldItemListInterface || $field->isEmpty()) { continue; } @@ -44,6 +44,11 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html continue; } + $access_result = $file->access('view', Drupal::currentUser(), TRUE); + if (!$access_result->isAllowed()) { + continue; + } + $uri = $file->getFileUri(); $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); $filename = $file->getFilename(); -- GitLab From 9921388ac06291d131592b737012cf4d666ffa35 Mon Sep 17 00:00:00 2001 From: "arash.poorakbar" <arash.poorakbar@gmail.com> Date: Tue, 27 May 2025 14:38:03 +0200 Subject: [PATCH 04/21] Replace content entity interface --- modules/file_attachment/markdownify_file_attachment.module | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 4d140bc..3e9adcb 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -7,7 +7,7 @@ declare(strict_types=1); -use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\file\FileInterface; @@ -16,7 +16,7 @@ use Drupal\file\FileInterface; */ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html, array $context): void { $entity = $context['entity'] ?? NULL; - if (!$entity instanceof ContentEntityInterface) { + if (!$entity instanceof FieldableEntityInterface) { return; } -- GitLab From 59fad118bb6131fb555f19491a07f331382cd6b4 Mon Sep 17 00:00:00 2001 From: "arash.poorakbar" <arash.poorakbar@gmail.com> Date: Tue, 27 May 2025 14:39:21 +0200 Subject: [PATCH 05/21] Delete doc from extensions --- modules/file_attachment/markdownify_file_attachment.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 3e9adcb..4975dc7 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -22,7 +22,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $output = ''; $allowed_extensions = [ - 'txt', 'json', 'yaml', 'yml', 'wsdl', 'rst', 'csv', 'tsv', 'rtf', 'doc', 'xml', + 'txt', 'json', 'yaml', 'yml', 'wsdl', 'rst', 'csv', 'tsv', 'rtf', 'xml', ]; $max_size = 1024 * 1024; -- GitLab From 18fb04b498d628672e0b342c2aa8167e389b7caa Mon Sep 17 00:00:00 2001 From: "arash.poorakbar" <arash.poorakbar@gmail.com> Date: Wed, 28 May 2025 12:48:38 +0200 Subject: [PATCH 06/21] Replace extension with mime type --- .../markdownify_file_attachment.module | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 4975dc7..f11fa7a 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -21,8 +21,10 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } $output = ''; - $allowed_extensions = [ - 'txt', 'json', 'yaml', 'yml', 'wsdl', 'rst', 'csv', 'tsv', 'rtf', 'xml', + $allowed_mime_types = [ + 'application/x-yaml', + 'application/json', + 'application/xml', ]; $max_size = 1024 * 1024; @@ -53,22 +55,22 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); $filename = $file->getFilename(); $filesize = $file->getSize(); - $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + $mime_type = $file->getMimeType(); - if (in_array($extension, $allowed_extensions) && $filesize < $max_size) { + if ((in_array($mime_type, $allowed_mime_types) || str_starts_with($mime_type, 'text')) && $filesize < $max_size) { $real_path = \Drupal::service('file_system')->realpath($uri); $content = @file_get_contents($real_path); $output .= <<<EOD - Attached file **{$filename}** with format **{$extension}** available at [{$url}] follows: \n - ```{$extension} + Attached file **{$filename}** with format **{$mime_type}** available at [{$url}] follows: \n + ```{$mime_type} {$content} ``` EOD; } else { - $output .= "\nAttached file {$filename} with format {$extension} is available at [$url]\n"; + $output .= "\nAttached file {$filename} with format {$mime_type} is available at [$url]\n"; } } } -- GitLab From 499b51f07956161728d6d5445f128b59876283e9 Mon Sep 17 00:00:00 2001 From: "arash.poorakbar" <arash.poorakbar@gmail.com> Date: Wed, 28 May 2025 13:05:55 +0200 Subject: [PATCH 07/21] Add cache bubble up --- .../markdownify_file_attachment.module | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index f11fa7a..0d57378 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -9,6 +9,7 @@ declare(strict_types=1); use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\EntityReferenceFieldItemListInterface; +use Drupal\Core\Render\BubbleableMetadata; use Drupal\file\FileInterface; /** @@ -51,6 +52,16 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html continue; } + /** @var \Drupal\Core\Render\RendererInterface $renderer */ + $renderer = \Drupal::service('renderer'); + if ($renderer->hasRenderContext()) { + $bubbleable = new BubbleableMetadata(); + $bubbleable->addCacheableDependency($access_result); + + $build = ['#cache' => ['#contexts' => $bubbleable->getCacheContexts()]]; + $renderer->render($build); + } + $uri = $file->getFileUri(); $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); $filename = $file->getFilename(); -- GitLab From d264154f0fb47b445cd03676632946ec9530852c Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <72541-arash.poorakbar@users.noreply.drupalcode.org> Date: Thu, 29 May 2025 09:18:47 +0000 Subject: [PATCH 08/21] Modify cacheability logic --- .../file_attachment/markdownify_file_attachment.module | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 0d57378..2b470b9 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -48,10 +48,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } $access_result = $file->access('view', Drupal::currentUser(), TRUE); - if (!$access_result->isAllowed()) { - continue; - } - + /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); if ($renderer->hasRenderContext()) { @@ -62,6 +59,10 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $renderer->render($build); } + if (!$access_result->isAllowed()) { + continue; + } + $uri = $file->getFileUri(); $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); $filename = $file->getFilename(); -- GitLab From 46368860722230047a432af948665ca92aac1269 Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <72541-arash.poorakbar@users.noreply.drupalcode.org> Date: Thu, 29 May 2025 09:25:36 +0000 Subject: [PATCH 09/21] Add new line --- modules/file_attachment/markdownify_file_attachment.module | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 2b470b9..c960f1d 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -74,12 +74,11 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $content = @file_get_contents($real_path); $output .= <<<EOD - Attached file **{$filename}** with format **{$mime_type}** available at [{$url}] follows: \n + \n Attached file **{$filename}** with format **{$mime_type}** available at [{$url}] follows: \n ```{$mime_type} {$content} - ``` + ``` \n EOD; - } else { $output .= "\nAttached file {$filename} with format {$mime_type} is available at [$url]\n"; -- GitLab From eaab5487d7f17ae65d963823417841139dbebbf6 Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <72541-arash.poorakbar@users.noreply.drupalcode.org> Date: Thu, 29 May 2025 09:31:17 +0000 Subject: [PATCH 10/21] Remove white space --- modules/file_attachment/markdownify_file_attachment.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index c960f1d..a4e3905 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -48,7 +48,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } $access_result = $file->access('view', Drupal::currentUser(), TRUE); - + /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); if ($renderer->hasRenderContext()) { -- GitLab From ad197729a9dc8cc7baf02c70daef0df42119eebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= <dezso.biczo@pronovix.com> Date: Thu, 29 May 2025 14:41:08 +0200 Subject: [PATCH 11/21] Fixes * Convert new lines to line breaks otherwise HTML to Markdown converter ignores them * Do not bubble up cacheability information in a loop rather collect it and bubble up once * Accept that from the MIME type we cannot guess neither the human readable format, nor the code to be used for highlighting - at least not without a static mapping, e.g, `text/plan` => `text`, `text/x-php` or `application/x-php` or `application/x-httpd-php` => `php`. --- .../markdownify_file_attachment.module | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index a4e3905..9673262 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -7,9 +7,9 @@ declare(strict_types=1); +use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\EntityReferenceFieldItemListInterface; -use Drupal\Core\Render\BubbleableMetadata; use Drupal\file\FileInterface; /** @@ -21,13 +21,17 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html return; } - $output = ''; + $file_attachment_lines = []; $allowed_mime_types = [ - 'application/x-yaml', + 'application/yaml', 'application/json', 'application/xml', ]; - $max_size = 1024 * 1024; + + // 1MB. + $max_file_embed_size = 1024 * 1024; + + $cacheability = new CacheableMetadata(); foreach ($entity->getFields() as $field) { // Skip fields that aren't referencing files. @@ -48,46 +52,47 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } $access_result = $file->access('view', Drupal::currentUser(), TRUE); - - /** @var \Drupal\Core\Render\RendererInterface $renderer */ - $renderer = \Drupal::service('renderer'); - if ($renderer->hasRenderContext()) { - $bubbleable = new BubbleableMetadata(); - $bubbleable->addCacheableDependency($access_result); - - $build = ['#cache' => ['#contexts' => $bubbleable->getCacheContexts()]]; - $renderer->render($build); - } + $cacheability->addCacheableDependency($access_result); if (!$access_result->isAllowed()) { continue; } - $uri = $file->getFileUri(); - $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); $filename = $file->getFilename(); $filesize = $file->getSize(); $mime_type = $file->getMimeType(); + $uri = $file->getFileUri(); + $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); - if ((in_array($mime_type, $allowed_mime_types) || str_starts_with($mime_type, 'text')) && $filesize < $max_size) { + if ((in_array($mime_type, $allowed_mime_types, TRUE) || str_starts_with($mime_type, 'text')) && $filesize <= $max_file_embed_size) { $real_path = \Drupal::service('file_system')->realpath($uri); - $content = @file_get_contents($real_path); - - $output .= <<<EOD - \n Attached file **{$filename}** with format **{$mime_type}** available at [{$url}] follows: \n - ```{$mime_type} - {$content} - ``` \n - EOD; + if (is_readable($real_path)) { + $content = @file_get_contents($real_path); + $line = "Attached file **{$filename}** with **{$mime_type}** MIME type available at [{$url}] follows:\n"; + $line .= <<<EOD + ``` + {$content} + ``` + EOD; + $file_attachment_lines[] = $line; + } } else { - $output .= "\nAttached file {$filename} with format {$mime_type} is available at [$url]\n"; + $file_attachment_lines[] = "Attached file {$filename} with {$mime_type} MIME type is available at {$url}."; } } } - if ($output) { - $html .= "\n\n" . $output; + /** @var \Drupal\Core\Render\RendererInterface $renderer */ + $renderer = \Drupal::service('renderer'); + if ($renderer->hasRenderContext()) { + $build = []; + $cacheability->applyTo($build); + $renderer->render($build); + } + + if ($file_attachment_lines !== []) { + $html .= nl2br("\n" . implode("\n\n", $file_attachment_lines)); } } -- GitLab From 09ec7364a7c0a233ab800b1ce132bf2c59c4f10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= <dezso.biczo@pronovix.com> Date: Thu, 29 May 2025 14:51:05 +0200 Subject: [PATCH 12/21] The entity is always a file in this case --- modules/file_attachment/markdownify_file_attachment.module | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 9673262..3f3dcf8 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -47,9 +47,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } foreach ($field->referencedEntities() as $file) { - if (!$file instanceof FileInterface) { - continue; - } + assert($file instanceof FileInterface); $access_result = $file->access('view', Drupal::currentUser(), TRUE); $cacheability->addCacheableDependency($access_result); -- GitLab From 6f2f1cf34bc5af31bbfd0d5e0582ae63ce6c8458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= <dezso.biczo@pronovix.com> Date: Thu, 29 May 2025 14:54:19 +0200 Subject: [PATCH 13/21] Spare words and lines --- .../file_attachment/markdownify_file_attachment.module | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 3f3dcf8..552e526 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -33,16 +33,13 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $cacheability = new CacheableMetadata(); + foreach ($entity->getFields() as $field) { - // Skip fields that aren't referencing files. + // Skip fields that not file reference fields. if (!$field instanceof EntityReferenceFieldItemListInterface || $field->isEmpty()) { continue; } - - $field_def = $field->getFieldDefinition(); - $target_type = $field_def->getFieldStorageDefinition()->getSetting('target_type') ?? NULL; - - if ($target_type !== 'file') { + if (($field->getFieldDefinition()->getFieldStorageDefinition()->getSetting('target_type') ?? '') !== 'file') { continue; } -- GitLab From 174b2a7c803739748a8c991eea40bab9f684a1c0 Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <arash.poorakbar@gmail.com> Date: Mon, 2 Jun 2025 14:50:30 +0200 Subject: [PATCH 14/21] Add admin form --- .../markdownify_file_attachment.schema.yml | 12 ++++ .../markdownify_file_attachment.module | 12 +--- .../markdownify_file_attachment.routing.yml | 7 ++ .../MarkdownifyFileAttachmentSettingsForm.php | 68 +++++++++++++++++++ 4 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml create mode 100644 modules/file_attachment/markdownify_file_attachment.routing.yml create mode 100644 modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php diff --git a/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml b/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml new file mode 100644 index 0000000..50d5f1a --- /dev/null +++ b/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml @@ -0,0 +1,12 @@ +markdownify_file_attachment.settings: + type: config_object + label: 'Markdownify File Attachment Settings' + mapping: + allowed_mime_types: + type: sequence + label: 'Allowed MIME types' + sequence: + - type: string + max_file_embed_size: + type: integer + label: 'Maximum file embed size (in bytes)' diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 552e526..13438c1 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -22,18 +22,12 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } $file_attachment_lines = []; - $allowed_mime_types = [ - 'application/yaml', - 'application/json', - 'application/xml', - ]; - - // 1MB. - $max_file_embed_size = 1024 * 1024; + $config = \Drupal::config('markdownify_file_attachment.settings'); + $allowed_mime_types = $config->get('allowed_mime_types') ?? ['text/plain', 'application/json']; + $max_file_embed_size = (int) $config->get('max_file_embed_size') ?: 1024 * 1024; $cacheability = new CacheableMetadata(); - foreach ($entity->getFields() as $field) { // Skip fields that not file reference fields. if (!$field instanceof EntityReferenceFieldItemListInterface || $field->isEmpty()) { diff --git a/modules/file_attachment/markdownify_file_attachment.routing.yml b/modules/file_attachment/markdownify_file_attachment.routing.yml new file mode 100644 index 0000000..2cb5c16 --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.routing.yml @@ -0,0 +1,7 @@ +markdownify_file_attachment.settings: + path: '/admin/config/content/markdownify-file-attachment' + defaults: + _form: '\Drupal\markdownify_file_attachment\Form\MarkdownifyFileAttachmentSettingsForm' + _title: 'Markdownify File Attachment Settings' + requirements: + _permission: 'administer site configuration' diff --git a/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php new file mode 100644 index 0000000..31f9c6d --- /dev/null +++ b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php @@ -0,0 +1,68 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\markdownify_file_attachment\Form; + +use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; + +/** + * Admin form for File Attachment settings. + */ +class MarkdownifyFileAttachmentSettingsForm extends ConfigFormBase { + + /** + * {@inheritdoc} + */ + public function getFormId(): string { + return 'markdownify_file_attachment_settings'; + } + + /** + * {@inheritdoc} + */ + protected function getEditableConfigNames(): array { + return ['markdownify_file_attachment.settings']; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state): array { + $config = $this->config('markdownify_file_attachment.settings'); + + $form['allowed_mime_types'] = [ + '#type' => 'textarea', + '#title' => $this->t('Allowed MIME types'), + '#description' => $this->t('Enter one MIME type per line.'), + '#default_value' => implode("\n", $config->get('allowed_mime_types') ?? [ + 'text/plain', + 'application/json', + ]), + ]; + + $form['max_file_embed_size'] = [ + '#type' => 'number', + '#title' => $this->t('Maximum file embed size (in bytes)'), + '#description' => $this->t('Files larger than this size will not be embedded inline.'), + '#default_value' => $config->get('max_file_embed_size') ?? (1024 * 1024), + '#min' => 0, + ]; + + return parent::buildForm($form, $form_state) + $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state): void { + $this->configFactory->getEditable('markdownify_file_attachment.settings') + ->set('allowed_mime_types', array_map('trim', explode("\n", $form_state->getValue('allowed_mime_types')))) + ->set('max_file_embed_size', (int) $form_state->getValue('max_file_embed_size')) + ->save(); + + parent::submitForm($form, $form_state); + } + +} -- GitLab From 16cdf7f202785f6a5c5da64adb694e84075f970b Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <arash.poorakbar@gmail.com> Date: Mon, 2 Jun 2025 15:23:18 +0200 Subject: [PATCH 15/21] Leverage new bubbleable metadata --- .../file_attachment/markdownify_file_attachment.module | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 13438c1..41eca7d 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -7,15 +7,15 @@ declare(strict_types=1); -use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\EntityReferenceFieldItemListInterface; +use Drupal\Core\Render\BubbleableMetadata; use Drupal\file\FileInterface; /** * Implements hook_markdownify_entity_html_alter(). */ -function markdownify_file_attachment_markdownify_entity_html_alter(string &$html, array $context): void { +function markdownify_file_attachment_markdownify_entity_html_alter(string &$html, array $context, ?BubbleableMetadata $metadata): void { $entity = $context['entity'] ?? NULL; if (!$entity instanceof FieldableEntityInterface) { return; @@ -26,8 +26,6 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $allowed_mime_types = $config->get('allowed_mime_types') ?? ['text/plain', 'application/json']; $max_file_embed_size = (int) $config->get('max_file_embed_size') ?: 1024 * 1024; - $cacheability = new CacheableMetadata(); - foreach ($entity->getFields() as $field) { // Skip fields that not file reference fields. if (!$field instanceof EntityReferenceFieldItemListInterface || $field->isEmpty()) { @@ -41,7 +39,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html assert($file instanceof FileInterface); $access_result = $file->access('view', Drupal::currentUser(), TRUE); - $cacheability->addCacheableDependency($access_result); + $metadata->addCacheableDependency($access_result); if (!$access_result->isAllowed()) { continue; @@ -76,7 +74,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $renderer = \Drupal::service('renderer'); if ($renderer->hasRenderContext()) { $build = []; - $cacheability->applyTo($build); + $metadata->applyTo($build); $renderer->render($build); } -- GitLab From 2418985e17bd927404289f5b2b98acb736639292 Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <arash.poorakbar@gmail.com> Date: Tue, 3 Jun 2025 11:21:03 +0200 Subject: [PATCH 16/21] Add config install --- .../install/markdownify_file_attachment.settings.yml | 4 ++++ .../file_attachment/markdownify_file_attachment.info.yml | 1 + modules/file_attachment/markdownify_file_attachment.module | 4 ++-- .../src/Form/MarkdownifyFileAttachmentSettingsForm.php | 7 ++----- 4 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 modules/file_attachment/config/install/markdownify_file_attachment.settings.yml diff --git a/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml new file mode 100644 index 0000000..2db196e --- /dev/null +++ b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml @@ -0,0 +1,4 @@ +allowed_mime_types: + - 'text/plain' + - 'application/json' +max_file_embed_size: 1048576 diff --git a/modules/file_attachment/markdownify_file_attachment.info.yml b/modules/file_attachment/markdownify_file_attachment.info.yml index 7ba81df..6329320 100644 --- a/modules/file_attachment/markdownify_file_attachment.info.yml +++ b/modules/file_attachment/markdownify_file_attachment.info.yml @@ -6,3 +6,4 @@ core_version_requirement: ^9 || ^10 || ^11 dependencies: - drupal:file - markdownify:markdownify +configure: markdownify_file_attachment.settings diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 41eca7d..4b68f89 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -23,8 +23,8 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $file_attachment_lines = []; $config = \Drupal::config('markdownify_file_attachment.settings'); - $allowed_mime_types = $config->get('allowed_mime_types') ?? ['text/plain', 'application/json']; - $max_file_embed_size = (int) $config->get('max_file_embed_size') ?: 1024 * 1024; + $allowed_mime_types = $config->get('allowed_mime_types'); + $max_file_embed_size = (int) $config->get('max_file_embed_size'); foreach ($entity->getFields() as $field) { // Skip fields that not file reference fields. diff --git a/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php index 31f9c6d..77c86ee 100644 --- a/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php +++ b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php @@ -36,17 +36,14 @@ class MarkdownifyFileAttachmentSettingsForm extends ConfigFormBase { '#type' => 'textarea', '#title' => $this->t('Allowed MIME types'), '#description' => $this->t('Enter one MIME type per line.'), - '#default_value' => implode("\n", $config->get('allowed_mime_types') ?? [ - 'text/plain', - 'application/json', - ]), + '#default_value' => implode("\n", $config->get('allowed_mime_types')), ]; $form['max_file_embed_size'] = [ '#type' => 'number', '#title' => $this->t('Maximum file embed size (in bytes)'), '#description' => $this->t('Files larger than this size will not be embedded inline.'), - '#default_value' => $config->get('max_file_embed_size') ?? (1024 * 1024), + '#default_value' => $config->get('max_file_embed_size'), '#min' => 0, ]; -- GitLab From 840642f74d44c7d77bd7df618c394295c07696b6 Mon Sep 17 00:00:00 2001 From: Christoph Weber <7725-ChristophWeber@users.noreply.drupalcode.org> Date: Wed, 4 Jun 2025 18:50:34 +0000 Subject: [PATCH 17/21] Omit formatting around filename, mime type and URL, because it is escaped during output and will not work. --- modules/file_attachment/markdownify_file_attachment.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 4b68f89..346e50e 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -55,7 +55,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $real_path = \Drupal::service('file_system')->realpath($uri); if (is_readable($real_path)) { $content = @file_get_contents($real_path); - $line = "Attached file **{$filename}** with **{$mime_type}** MIME type available at [{$url}] follows:\n"; + $line = "Attached file {$filename} with {$mime_type} MIME type available at {$url} follows:\n"; $line .= <<<EOD ``` {$content} -- GitLab From d409c217033061c65038c7bbaf3807c54f3ba945 Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <arash.poorakbar@gmail.com> Date: Thu, 5 Jun 2025 14:28:09 +0200 Subject: [PATCH 18/21] Revert back to extensions --- .../markdownify_file_attachment.settings.yml | 10 ++++++---- .../schema/markdownify_file_attachment.schema.yml | 6 +++--- .../markdownify_file_attachment.module | 14 ++++++++------ .../Form/MarkdownifyFileAttachmentSettingsForm.php | 14 +++++++------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml index 2db196e..d0c9190 100644 --- a/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml +++ b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml @@ -1,4 +1,6 @@ -allowed_mime_types: - - 'text/plain' - - 'application/json' -max_file_embed_size: 1048576 +allowed_extensions: + - 'txt' + - 'yml' + - 'wsdl' + - 'json' +max_file_embed_size: '1 MB' diff --git a/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml b/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml index 50d5f1a..0c9e9a2 100644 --- a/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml +++ b/modules/file_attachment/config/schema/markdownify_file_attachment.schema.yml @@ -2,11 +2,11 @@ markdownify_file_attachment.settings: type: config_object label: 'Markdownify File Attachment Settings' mapping: - allowed_mime_types: + allowed_extensions: type: sequence - label: 'Allowed MIME types' + label: 'Allowed extensions' sequence: - type: string max_file_embed_size: - type: integer + type: bytes label: 'Maximum file embed size (in bytes)' diff --git a/modules/file_attachment/markdownify_file_attachment.module b/modules/file_attachment/markdownify_file_attachment.module index 346e50e..b2ea999 100644 --- a/modules/file_attachment/markdownify_file_attachment.module +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -7,6 +7,8 @@ declare(strict_types=1); +use Drupal\Component\Utility\Bytes; +use Drupal\Component\Utility\Environment; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\Core\Render\BubbleableMetadata; @@ -23,8 +25,8 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $file_attachment_lines = []; $config = \Drupal::config('markdownify_file_attachment.settings'); - $allowed_mime_types = $config->get('allowed_mime_types'); - $max_file_embed_size = (int) $config->get('max_file_embed_size'); + $allowed_extensions = $config->get('allowed_extensions'); + $max_file_embed_size = min(Bytes::toNumber($config->get('max_file_embed_size') ?? 0), Environment::getUploadMaxSize()); foreach ($entity->getFields() as $field) { // Skip fields that not file reference fields. @@ -47,15 +49,15 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html $filename = $file->getFilename(); $filesize = $file->getSize(); - $mime_type = $file->getMimeType(); + $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $uri = $file->getFileUri(); $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); - if ((in_array($mime_type, $allowed_mime_types, TRUE) || str_starts_with($mime_type, 'text')) && $filesize <= $max_file_embed_size) { + if (in_array($extension, $allowed_extensions, TRUE) && $filesize <= $max_file_embed_size) { $real_path = \Drupal::service('file_system')->realpath($uri); if (is_readable($real_path)) { $content = @file_get_contents($real_path); - $line = "Attached file {$filename} with {$mime_type} MIME type available at {$url} follows:\n"; + $line = "Attached file {$filename} with {$extension} extension available at {$url} follows:\n"; $line .= <<<EOD ``` {$content} @@ -65,7 +67,7 @@ function markdownify_file_attachment_markdownify_entity_html_alter(string &$html } } else { - $file_attachment_lines[] = "Attached file {$filename} with {$mime_type} MIME type is available at {$url}."; + $file_attachment_lines[] = "Attached file {$filename} with {$extension} extension is available at {$url}."; } } } diff --git a/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php index 77c86ee..f77df88 100644 --- a/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php +++ b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php @@ -32,15 +32,15 @@ class MarkdownifyFileAttachmentSettingsForm extends ConfigFormBase { public function buildForm(array $form, FormStateInterface $form_state): array { $config = $this->config('markdownify_file_attachment.settings'); - $form['allowed_mime_types'] = [ + $form['allowed_extensions'] = [ '#type' => 'textarea', - '#title' => $this->t('Allowed MIME types'), - '#description' => $this->t('Enter one MIME type per line.'), - '#default_value' => implode("\n", $config->get('allowed_mime_types')), + '#title' => $this->t('Allowed file extensions'), + '#description' => $this->t('Enter one extension per line.'), + '#default_value' => implode("\n", $config->get('allowed_extensions')), ]; $form['max_file_embed_size'] = [ - '#type' => 'number', + '#type' => 'textfield', '#title' => $this->t('Maximum file embed size (in bytes)'), '#description' => $this->t('Files larger than this size will not be embedded inline.'), '#default_value' => $config->get('max_file_embed_size'), @@ -55,8 +55,8 @@ class MarkdownifyFileAttachmentSettingsForm extends ConfigFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state): void { $this->configFactory->getEditable('markdownify_file_attachment.settings') - ->set('allowed_mime_types', array_map('trim', explode("\n", $form_state->getValue('allowed_mime_types')))) - ->set('max_file_embed_size', (int) $form_state->getValue('max_file_embed_size')) + ->set('allowed_extensions', array_map('trim', explode("\n", $form_state->getValue('allowed_extensions')))) + ->set('max_file_embed_size', $form_state->getValue('max_file_embed_size')) ->save(); parent::submitForm($form, $form_state); -- GitLab From e1e8935f067095a30c1ac52b9901332332cfe6ea Mon Sep 17 00:00:00 2001 From: Arash Poorakbar <arash.poorakbar@gmail.com> Date: Thu, 5 Jun 2025 15:51:51 +0200 Subject: [PATCH 19/21] Add menu link --- .../markdownify_file_attachment.links.menu.yml | 5 +++++ .../file_attachment/markdownify_file_attachment.routing.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 modules/file_attachment/markdownify_file_attachment.links.menu.yml diff --git a/modules/file_attachment/markdownify_file_attachment.links.menu.yml b/modules/file_attachment/markdownify_file_attachment.links.menu.yml new file mode 100644 index 0000000..315bb6c --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.links.menu.yml @@ -0,0 +1,5 @@ +markdownify_file_attachment.settings: + title: 'Markdownify File Attachment Settings' + route_name: markdownify_file_attachment.settings + description: 'Configure file embedding settings' + parent: system.admin_config_services diff --git a/modules/file_attachment/markdownify_file_attachment.routing.yml b/modules/file_attachment/markdownify_file_attachment.routing.yml index 2cb5c16..c97ecce 100644 --- a/modules/file_attachment/markdownify_file_attachment.routing.yml +++ b/modules/file_attachment/markdownify_file_attachment.routing.yml @@ -1,5 +1,5 @@ markdownify_file_attachment.settings: - path: '/admin/config/content/markdownify-file-attachment' + path: '/admin/config/services/markdownify/file-attachment' defaults: _form: '\Drupal\markdownify_file_attachment\Form\MarkdownifyFileAttachmentSettingsForm' _title: 'Markdownify File Attachment Settings' -- GitLab From 62189d0ea509596794d3cc1114c831a40fefe966 Mon Sep 17 00:00:00 2001 From: Christoph Weber <7725-ChristophWeber@users.noreply.drupalcode.org> Date: Fri, 6 Jun 2025 16:02:49 +0000 Subject: [PATCH 20/21] Added yaml to allowed file extensions due to new IANA and IETF preference. --- .../config/install/markdownify_file_attachment.settings.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml index d0c9190..9f2e781 100644 --- a/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml +++ b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml @@ -1,6 +1,7 @@ allowed_extensions: - 'txt' - 'yml' + - 'yaml' - 'wsdl' - 'json' max_file_embed_size: '1 MB' -- GitLab From b7c1bf6bf441f8066e4a38b9a0eef548a3545c9e Mon Sep 17 00:00:00 2001 From: Christoph Weber <7725-ChristophWeber@users.noreply.drupalcode.org> Date: Fri, 6 Jun 2025 16:29:00 +0000 Subject: [PATCH 21/21] Require ^10.2 to accommodate #config_target --- modules/file_attachment/markdownify_file_attachment.info.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/file_attachment/markdownify_file_attachment.info.yml b/modules/file_attachment/markdownify_file_attachment.info.yml index 6329320..a710a0a 100644 --- a/modules/file_attachment/markdownify_file_attachment.info.yml +++ b/modules/file_attachment/markdownify_file_attachment.info.yml @@ -2,7 +2,7 @@ name: Markdownify File Attachment description: This module provides support for rendering files in the markdown. package: AI type: module -core_version_requirement: ^9 || ^10 || ^11 +core_version_requirement: ^10.2 || ^11 dependencies: - drupal:file - markdownify:markdownify -- GitLab