diff --git a/.ddev/.env.example b/.ddev/.env.example index df5aa81207..31d56ff1a3 100644 --- a/.ddev/.env.example +++ b/.ddev/.env.example @@ -18,7 +18,7 @@ MASS_BYPASS_RATE_LIMIT= LOOKER_STUDIO_URL= #Azure AD. Only needed if you are doing Azure work -AZURE_AD_CLIENT_SECRET +AZURE_AD_CLIENT_SECRET= # Enable the akamai or acquia_purge purger in local development. # MASS_PURGERS=akamai @@ -81,3 +81,7 @@ AWS_BEDROCK_ROLE_SESSION_NAME='' AWS_BEDROCK_ACCESS_KEY_ID='' AWS_BEDROCK_SECRET_ACCESS_KEY='' AWS_BEDROCK_REGION=us-east-1 + +#Adobe PDF services settings. +ADOBE_PDF_SERVICES_CLIENT_ID='' +ADOBE_PDF_SERVICES_CLIENT_SECRET='' diff --git a/changelogs/DP-43783.yml b/changelogs/DP-43783.yml new file mode 100644 index 0000000000..c980ddd535 --- /dev/null +++ b/changelogs/DP-43783.yml @@ -0,0 +1,41 @@ +# +# Write your changelog entry here. Every pull request must have a changelog yml file. +# +# Change types: +# ############################################################################# +# You can use one of the following types: +# - Added: For new features. +# - Changed: For changes to existing functionality. +# - Deprecated: For soon-to-be removed features. +# - Removed: For removed features. +# - Fixed: For any bug fixes. +# - Security: In case of vulnerabilities. +# +# Format +# ############################################################################# +# The format is crucial. Please follow the examples below. For reference, the requirements are: +# - All 3 parts are required and you must include "Type", "description" and "issue". +# - "Type" must be left aligned and followed by a colon. +# - "description" must be indented with 2 spaces followed by a colon +# - "issue" must be indented with 4 spaces followed by a colon. +# - "issue" is for the Jira ticket number only e.g. DP-1234 +# - No extra spaces, indents, or blank lines are allowed. +# +# Example: +# ############################################################################# +# Fixed: +# - description: Fixes scrolling on edit pages in Safari. +# issue: DP-13314 +# +# You may add more than 1 description & issue for each type using the following format: +# Changed: +# - description: Automating the release branch. +# issue: DP-10166 +# - description: Second change item that needs a description. +# issue: DP-19875 +# - description: Third change item that needs a description along with an issue. +# issue: DP-19843 +# +Added: + - description: PDF accessibility checker module. + issue: DP-43783 diff --git a/composer.json b/composer.json index ff645c5592..3261154952 100644 --- a/composer.json +++ b/composer.json @@ -233,6 +233,7 @@ "drupal/paragraphs": "^1.10", "drupal/pathauto": "^1.13", "drupal/pathologic": "^2", + "drupal/pdf_services": "^1.0@alpha", "drupal/phpstorm_metadata": "^1.0@alpha", "drupal/prepopulate": "^2.0", "drupal/private_files_download_permission": "^3", @@ -486,6 +487,9 @@ "drupal/password_policy": { "Can't edit user profile because password policy validates even when password unchanged": "https://www.drupal.org/files/issues/2020-03-19/password_policy-empty-password-skip-validation-2971079-37.patch" }, + "drupal/pdf_services": { + "A11y report in the edit form (https://www.drupal.org/project/pdf_services/issues/3530902#comment-16387775)": "https://www.drupal.org/files/issues/2025-12-18/pdf_services_3530902_3.patch" + }, "drupal/redirect": { "Add an intermediate redirect (https://www.drupal.org/project/redirect/issues/3162696#comment-15085388)": "https://www.drupal.org/files/issues/2023-05-31/tmp.diff", "Filter by redirect destination does not work with URL alias (https://www.drupal.org/project/redirect/issues/2981544) (See DP-31078 before replacing)": "https://www.drupal.org/files/issues/2024-08-13/2981544-45.patch", diff --git a/composer.lock b/composer.lock index be9f7a0999..f79c0d6131 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7b9eaac987df7c8956b05827d445e02c", + "content-hash": "5e689e114991e27edc11e27a0ee9951c", "packages": [ { "name": "akamai-open/edgegrid-auth", @@ -9065,6 +9065,66 @@ "source": "https://git.drupalcode.org/project/pathologic" } }, + { + "name": "drupal/pdf_services", + "version": "1.0.0-alpha4", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/pdf_services.git", + "reference": "1.0.0-alpha4" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/pdf_services-1.0.0-alpha4.zip", + "reference": "1.0.0-alpha4", + "shasum": "e067deb3f9a09378ec3acaf654fed89c16173942" + }, + "require": { + "drupal/core": "^10", + "ext-json": "*", + "guzzlehttp/guzzle": "^7.0" + }, + "require-dev": { + "drupal/symfony_mailer_lite": "^1.0", + "drupal/views_bulk_operations": "^4.0", + "drush/drush": "^12.0" + }, + "suggest": { + "drupal/file": "Required for handling file uploads and management" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "1.0.0-alpha4", + "datestamp": "1760550272", + "security-coverage": { + "status": "not-covered", + "message": "Project has not opted into security advisory coverage!" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Nicholas Stees (nicholass)", + "homepage": "https://www.drupal.org/user/3735949", + "role": "Maintainer" + }, + { + "name": "nicholass", + "homepage": "https://www.drupal.org/user/3487851" + } + ], + "description": "Integrates with Adobe PDF Services API for PDF analysis and optimization.", + "homepage": "https://www.drupal.org/project/pdf_services", + "support": { + "source": "https://git.drupalcode.org/project/pdf_services", + "issues": "https://www.drupal.org/project/issues/pdf_services" + } + }, { "name": "drupal/phpstorm_metadata", "version": "1.0.0-alpha4", @@ -26606,6 +26666,7 @@ "drupal/imageapi_optimize_resmushit": 10, "drupal/openid_connect": 20, "drupal/openid_connect_windows_aad": 20, + "drupal/pdf_services": 15, "drupal/phpstorm_metadata": 15, "drupal/views_taxonomy_term_name_into_id": 15, "drupaltest/queue-runner-trait": 20, diff --git a/conf/drupal/config/core.entity_form_display.media.document.default.yml b/conf/drupal/config/core.entity_form_display.media.document.default.yml index 75edfae1fd..223d61ba65 100644 --- a/conf/drupal/config/core.entity_form_display.media.document.default.yml +++ b/conf/drupal/config/core.entity_form_display.media.document.default.yml @@ -25,8 +25,8 @@ dependencies: - datetime - entity_reference_tree - field_group - - file - path + - pdf_services third_party_settings: field_group: group_timeframe: @@ -210,7 +210,7 @@ content: placeholder: '' third_party_settings: { } field_upload_file: - type: file_generic + type: pdf_file_widget weight: 5 region: content settings: diff --git a/conf/drupal/config/core.extension.yml b/conf/drupal/config/core.extension.yml index 2cb9a267a5..76bbc19be0 100644 --- a/conf/drupal/config/core.extension.yml +++ b/conf/drupal/config/core.extension.yml @@ -197,6 +197,7 @@ module: path: 0 path_alias: 0 pathologic: 0 + pdf_services: 0 pfdp: 0 phpass: 0 prepopulate: 0 diff --git a/conf/drupal/config/field.field.media.document.field_upload_file.yml b/conf/drupal/config/field.field.media.document.field_upload_file.yml index 91c1420893..a0d9fb10af 100644 --- a/conf/drupal/config/field.field.media.document.field_upload_file.yml +++ b/conf/drupal/config/field.field.media.document.field_upload_file.yml @@ -7,6 +7,13 @@ dependencies: - media.type.document module: - file + - pdf_services +third_party_settings: + pdf_services: + check_properties: 0 + check_accessibility: 1 + page_size_threshold: 500000 + compression_level: NONE id: media.document.field_upload_file field_name: field_upload_file entity_type: media diff --git a/conf/drupal/config/highlightjs_input_filter.settings.yml b/conf/drupal/config/highlightjs_input_filter.settings.yml index 1b3aabfc42..74f4d999d9 100644 --- a/conf/drupal/config/highlightjs_input_filter.settings.yml +++ b/conf/drupal/config/highlightjs_input_filter.settings.yml @@ -1,4 +1,4 @@ _core: default_config_hash: Y83OAt1EvYg3cu-J11xYwuY10E01vRsSnm-vs3-1XMQ enable_copy_button: false -theme: a11y-dark \ No newline at end of file +theme: a11y-dark diff --git a/conf/drupal/config/pdf_services.adobe_embed_settings.yml b/conf/drupal/config/pdf_services.adobe_embed_settings.yml new file mode 100644 index 0000000000..b00925e242 --- /dev/null +++ b/conf/drupal/config/pdf_services.adobe_embed_settings.yml @@ -0,0 +1 @@ +client_id: '' diff --git a/conf/drupal/config/pdf_services.settings.yml b/conf/drupal/config/pdf_services.settings.yml new file mode 100644 index 0000000000..bba610ef6e --- /dev/null +++ b/conf/drupal/config/pdf_services.settings.yml @@ -0,0 +1,12 @@ +_core: + default_config_hash: azSZG6PzCOEObVe6w8oHNHYnnpmshoZLUIedRu-EsjY +processing_enabled: 1 +client_id: 'Random string' +client_secret: 'Random string' +batch_size: '5' +retry_limit: '3' +page_size_threshold: 500000 +email_notifications: + enabled: 0 + include_report: 0 +notification_fallback_uid: null diff --git a/conf/drupal/config/user.role.author.yml b/conf/drupal/config/user.role.author.yml index 1d95a86cc2..208444b715 100644 --- a/conf/drupal/config/user.role.author.yml +++ b/conf/drupal/config/user.role.author.yml @@ -59,6 +59,7 @@ dependencies: - mass_workbench_ui - media - node + - pdf_services - quick_node_clone - rabbit_hole - scheduled_transitions @@ -84,6 +85,7 @@ permissions: - 'access user contact forms' - 'access user profiles' - 'access video_browser entity browser pages' + - 'check pdf accessibility' - 'clone advisory content' - 'clone alert content' - 'clone binder content' diff --git a/conf/drupal/config/user.role.editor.yml b/conf/drupal/config/user.role.editor.yml index 68df19694f..955547d3a7 100644 --- a/conf/drupal/config/user.role.editor.yml +++ b/conf/drupal/config/user.role.editor.yml @@ -55,14 +55,15 @@ dependencies: - layout_paragraphs_permissions - mass_admin_toolbar - mass_analytics - - mass_friendly_redirects - mass_bulk_file_replace + - mass_friendly_redirects - mass_hierarchy - mass_validation - mass_views - mass_workbench_ui - media - node + - pdf_services - quick_node_clone - rabbit_hole - scheduled_transitions @@ -116,6 +117,7 @@ permissions: - 'add scheduled transitions node rules' - 'add scheduled transitions node service_page' - 'administer nodes' + - 'check pdf accessibility' - 'clone advisory content' - 'clone alert content' - 'clone binder content' diff --git a/conf/drupal/config/views.view.document_accessibility_report.yml b/conf/drupal/config/views.view.document_accessibility_report.yml new file mode 100644 index 0000000000..030a3f0c4c --- /dev/null +++ b/conf/drupal/config/views.view.document_accessibility_report.yml @@ -0,0 +1,587 @@ +uuid: 1cb56394-35de-4412-b398-36ab36d41f99 +langcode: en +status: true +dependencies: + config: + - field.storage.media.field_organizations + - field.storage.media.field_title + module: + - file + - media + - pdf_services +id: document_accessibility_report +label: 'Document accessibility report' +module: views +description: '' +tag: '' +base_table: pdf_accessibility_result +base_field: id +display: + default: + id: default + display_title: Default + display_plugin: default + position: 0 + display_options: + fields: + rendered_entity: + id: rendered_entity + table: pdf_accessibility_result + field: rendered_entity + relationship: none + group_type: group + admin_label: '' + entity_type: null + entity_field: null + plugin_id: rendered_entity + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + view_mode: default + passes: + id: passes + table: pdf_accessibility_result + field: passes + relationship: none + group_type: group + admin_label: '' + entity_type: pdf_accessibility_result + plugin_id: boolean + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + type: yes-no + type_custom_true: '' + type_custom_false: '' + not: false + name: + id: name + table: media_field_data + field: name + relationship: reverse_field_upload_file_media + group_type: group + admin_label: '' + entity_type: media + entity_field: name + plugin_id: field + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_organizations: + id: field_organizations + table: media__field_organizations + field: field_organizations + relationship: reverse_field_upload_file_media + group_type: group + admin_label: '' + plugin_id: field + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: true + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + status: + id: status + table: media_field_data + field: status + relationship: reverse_field_upload_file_media + group_type: group + admin_label: '' + entity_type: media + entity_field: status + plugin_id: field + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: default + format_custom_false: '' + format_custom_true: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_title: + id: field_title + table: media__field_title + field: field_title + relationship: reverse_field_upload_file_media + group_type: group + admin_label: '' + plugin_id: field + label: 'Document title' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + created: + id: created + table: pdf_accessibility_result + field: created + relationship: none + group_type: group + admin_label: '' + entity_type: pdf_accessibility_result + plugin_id: date + label: 'Check Date' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + date_format: short_date_only + custom_date_format: '' + timezone: '' + pager: + type: mini + options: + offset: 0 + pagination_heading_level: h4 + items_per_page: 10 + total_pages: null + id: 0 + tags: + next: ›› + previous: ‹‹ + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + access: + type: none + options: { } + cache: + type: tag + options: { } + empty: { } + sorts: { } + arguments: { } + filters: { } + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + columns: + rendered_entity: rendered_entity + passes: passes + name: name + field_organizations: field_organizations + status: status + default: '-1' + info: + rendered_entity: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + passes: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + name: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + field_organizations: + align: '' + separator: '' + empty_column: false + responsive: '' + status: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + override: true + sticky: false + summary: '' + empty_table: false + caption: '' + description: '' + row: + type: fields + options: + default_field_elements: true + inline: { } + separator: '' + hide_empty: false + query: + type: views_query + options: + query_comment: '' + disable_sql_rewrite: false + distinct: false + disable_automatic_base_fields: false + replica: false + query_tags: { } + relationships: + file: + id: file + table: pdf_accessibility_result + field: file + relationship: none + group_type: group + admin_label: File + entity_type: pdf_accessibility_result + plugin_id: standard + required: true + reverse_field_upload_file_media: + id: reverse_field_upload_file_media + table: file_managed + field: reverse_field_upload_file_media + relationship: file + group_type: group + admin_label: field_upload_file + entity_type: file + plugin_id: entity_reverse + required: true + header: { } + footer: { } + display_extenders: + metatag_display_extender: + metatags: { } + tokenize: false + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + tags: + - 'config:field.storage.media.field_organizations' + - 'config:field.storage.media.field_title' diff --git a/docroot/sites/default/settings.php b/docroot/sites/default/settings.php index 1e92a8aaf4..6e7127af87 100644 --- a/docroot/sites/default/settings.php +++ b/docroot/sites/default/settings.php @@ -104,6 +104,16 @@ $config['key.key.real_aes']['key_provider_settings']['key_value'] = getenv('REAL_AES_KEY_VALUE'); $config['geocoder.geocoder_provider.opencage']['configuration']['apiKey'] = getenv('GEOCODER_OPENCAGE_API_KEY'); +// Check in env var is defined. Adobe PDF Services API Credentials +if (!empty(getenv('ADOBE_PDF_SERVICES_CLIENT_ID'))) { + $config['pdf_services.settings']['client_id'] = getenv('ADOBE_PDF_SERVICES_CLIENT_ID'); +} + +if (!empty(getenv('ADOBE_PDF_SERVICES_CLIENT_SECRET'))) { + $config['pdf_services.settings']['client_secret'] = getenv('ADOBE_PDF_SERVICES_CLIENT_SECRET'); +} + + // Add database connection for Service Details migration. // Environment indicator. See https://architecture.lullabot.com/adr/20210609-environment-indicator/