Async validators for s3fs_cors_file form element

Created on 16 September 2024, 5 months ago

Problem/Motivation

I need to add custom validation for video files by duration and it’s impossible with the currentDrupal.s3fsCors implementation because video duration validation is async (we need to preload file metadata to get the duration).

To resolve this issue we need to make theDrupal.s3fsCors.validateFile function async and I think, in this case, it’ll be a good idea to do some refactoring and change callbacks with promises.

Proposed resolution

I suggest refactoring the current Drupal.s3fsCors implementation, we need to extract each AJAX request into its function and call them in a promise chain. After that, we can extend the Drupal.s3fsCors to add the possibility of using custom validators.

Custom validators can be implemented like Drupal have implemented AJAX commands:

  1. Move all validator functions intoDrupal.s3fsCors.validators object
  2. each validator should implement this validatorFunction(file: File, settings: any): Promise interface where
    • file - is the file object
    • settings - is the settings that we passed from the back-end, which can be any value
    • Promise<void> - it should return a resolved promise if it passes validation or rejected promise with an error message
  3. Update how the back-end adds validations to the settings, we need to have all validators under validators property like
    $js_settings['validators']['extension_list'] = implode(',', array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])));
    $js_settings['validators']['max_size'] = $max_filesize;
    
  4. update the Drupal.s3fsCors.validateFile to run all validations from settings

After these changes, new validators can be added to the s3fs_cors_file widget by following instructions:

  1. Create new functions on Drupal.s3fsCors.validators namespace like this
    Drupal.s3fsCors.validators.video_duration = (file, maxDuration) => new Promise((resolve, reject) => {
      const video = document.createElement('video');
      video.preload = 'metadata';
      video.onloadedmetadata = function () {
        window.URL.revokeObjectURL(video.src);
        if (video.duration > maxDuration) {
          reject(Drupal.t('Please upload video up to %max_duration minutes.', { '%max_duration': maxDuration }));
        }
        resolve();
      };
      video.onerror = function () {
        resolve();
      };
      video.src = URL.createObjectURL(file);
    });
    
  2. Add validation to the widget for example with hook_form_alter
    function custom_module_form_media_video_add_form_alter(&$form, FormStateInterface $form_state, $form_id): void {
      $form['#after_build'][] = 'custom_module_form_media_video_add_form_after_build';
    }
    
    function custom_module_form_media_video_add_form_after_build($form, FormStateInterface $form_state): array {
      // Add validation to restrict videos longer then 5 min.
      $form['field_video']['widget'][0]['upload']['#attached']['drupalSettings']['s3fs_cors']['field_video']['validators']['max_duration'] = 300;
      return $form;
    }
    

This feature request can be split into two issues: one for refactoring and another for custom validation functionalities.

✨ Feature request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡¦Ukraine chizh273

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Production build 0.71.5 2024