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 0000000000000000000000000000000000000000..9f2e781e74e39626cb0e49fb41f5e60c8664e2e4 --- /dev/null +++ b/modules/file_attachment/config/install/markdownify_file_attachment.settings.yml @@ -0,0 +1,7 @@ +allowed_extensions: + - 'txt' + - 'yml' + - 'yaml' + - '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 new file mode 100644 index 0000000000000000000000000000000000000000..0c9e9a2eef3146dccd81704a42b323eecb4fda5d --- /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_extensions: + type: sequence + label: 'Allowed extensions' + sequence: + - type: string + max_file_embed_size: + type: bytes + label: 'Maximum file embed size (in bytes)' 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 0000000000000000000000000000000000000000..a710a0ab3d22080efa0d40677ba68124408daf64 --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.info.yml @@ -0,0 +1,9 @@ +name: Markdownify File Attachment +description: This module provides support for rendering files in the markdown. +package: AI +type: module +core_version_requirement: ^10.2 || ^11 +dependencies: + - drupal:file + - markdownify:markdownify +configure: markdownify_file_attachment.settings 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 0000000000000000000000000000000000000000..315bb6c98edab5a0a3ec7a5e42f530303b331550 --- /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.module b/modules/file_attachment/markdownify_file_attachment.module new file mode 100644 index 0000000000000000000000000000000000000000..b2ea999d44f0f0fb31bdcba088f52afa0c75eec7 --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.module @@ -0,0 +1,87 @@ +<?php + +/** + * @file + * Main module file for Markdownify File Attachment. + */ + +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; +use Drupal\file\FileInterface; + +/** + * Implements hook_markdownify_entity_html_alter(). + */ +function markdownify_file_attachment_markdownify_entity_html_alter(string &$html, array $context, ?BubbleableMetadata $metadata): void { + $entity = $context['entity'] ?? NULL; + if (!$entity instanceof FieldableEntityInterface) { + return; + } + + $file_attachment_lines = []; + $config = \Drupal::config('markdownify_file_attachment.settings'); + $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. + if (!$field instanceof EntityReferenceFieldItemListInterface || $field->isEmpty()) { + continue; + } + if (($field->getFieldDefinition()->getFieldStorageDefinition()->getSetting('target_type') ?? '') !== 'file') { + continue; + } + + foreach ($field->referencedEntities() as $file) { + assert($file instanceof FileInterface); + + $access_result = $file->access('view', Drupal::currentUser(), TRUE); + $metadata->addCacheableDependency($access_result); + + if (!$access_result->isAllowed()) { + continue; + } + + $filename = $file->getFilename(); + $filesize = $file->getSize(); + $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + $uri = $file->getFileUri(); + $url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri); + + 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 {$extension} extension available at {$url} follows:\n"; + $line .= <<<EOD + ``` + {$content} + ``` + EOD; + $file_attachment_lines[] = $line; + } + } + else { + $file_attachment_lines[] = "Attached file {$filename} with {$extension} extension is available at {$url}."; + } + } + } + + /** @var \Drupal\Core\Render\RendererInterface $renderer */ + $renderer = \Drupal::service('renderer'); + if ($renderer->hasRenderContext()) { + $build = []; + $metadata->applyTo($build); + $renderer->render($build); + } + + if ($file_attachment_lines !== []) { + $html .= nl2br("\n" . implode("\n\n", $file_attachment_lines)); + } + +} 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 0000000000000000000000000000000000000000..c97ecce0b41c5edb9ce6ac240066ecff86bb7c64 --- /dev/null +++ b/modules/file_attachment/markdownify_file_attachment.routing.yml @@ -0,0 +1,7 @@ +markdownify_file_attachment.settings: + path: '/admin/config/services/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 0000000000000000000000000000000000000000..f77df88b57880df3a83fe4785d9df162700d7fe3 --- /dev/null +++ b/modules/file_attachment/src/Form/MarkdownifyFileAttachmentSettingsForm.php @@ -0,0 +1,65 @@ +<?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_extensions'] = [ + '#type' => 'textarea', + '#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' => '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'), + '#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_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); + } + +}