diff --git a/composer.json b/composer.json index 6b800ba..8c9006c 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,8 @@ "dpc-sdp/tide_core": "3.2.5", "drupal/token_conditions": "dev-compatible-with-drupal-9", "drupal/webform": "^6.1@beta", + "drupal/webform_rest": "^4.0", + "drupal/restui": "^1.21", "choices/choices": "9.0.1", "codemirror/codemirror": "5.53.2", "jquery/inputmask": "5.0.5", @@ -18,6 +20,9 @@ "drupal/webform": { "Filtering by category doesn't work - https://www.drupal.org/project/webform/issues/3313766": "https://www.drupal.org/files/issues/2022-10-07/3313766-8.patch", "Exporting webform submission as batch does not allowed for extended field due to static method - https://www.drupal.org/project/webform/issues/3348336#comment-14969352": "https://www.drupal.org/files/issues/2023-03-16/exporting-webform-submission-static-batch-process-3348336-3.patch" + }, + "drupal/webform_rest": { + "Send/Upload files - https://www.drupal.org/project/webform_rest/issues/2899902": "https://www.drupal.org/files/issues/2023-05-10/webform_rest-add_file_upload_resource-2899902-56-v4.x.patch" } } }, diff --git a/config/optional/rest.resource.webform_rest_file_upload.yml b/config/optional/rest.resource.webform_rest_file_upload.yml new file mode 100644 index 0000000..4fdc00e --- /dev/null +++ b/config/optional/rest.resource.webform_rest_file_upload.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + module: + - serialization + - user + - webform_rest +id: webform_rest_file_upload +plugin_id: webform_rest_file_upload +granularity: resource +configuration: + methods: + - POST + formats: + - json + authentication: + - cookie diff --git a/config/optional/webform.settings.yml b/config/optional/webform.settings.yml index f4b5aef..7d4f5eb 100644 --- a/config/optional/webform.settings.yml +++ b/config/optional/webform.settings.yml @@ -123,7 +123,6 @@ element: fieldset: fieldset item: item language_select: language_select - managed_file: managed_file range: range search: search tableselect: tableselect @@ -140,7 +139,6 @@ element: webform_contact: webform_contact webform_custom_composite: webform_custom_composite webform_document_file: webform_document_file - webform_element: webform_element webform_email_confirm: webform_email_confirm webform_email_multiple: webform_email_multiple webform_entity_checkboxes: webform_entity_checkboxes @@ -178,11 +176,11 @@ html_editor: format: '' tidy: true file: - file_public: false + file_public: true file_private_redirect: true file_private_redirect_message: 'Please login to access the uploaded file.' - default_max_filesize: '' - default_managed_file_extensions: 'gif jpg png bmp eps tif pict psd txt rtf html odf pdf doc docx ppt pptx xls xlsx xml avi mov mp3 ogg wav bz2 dmg gz jar rar sit svg tar zip' + default_max_filesize: '10 MB' + default_managed_file_extensions: 'docx jpg png pdf csv zip xls mp3 mp4 wav avi' default_audio_file_extensions: 'mp3 ogg wav' default_document_file_extensions: 'txt rtf pdf doc docx odt ppt pptx odp xls xlsx ods' default_image_file_extensions: 'gif jpg png svg' diff --git a/src/TideWebformSubmissionListBuilder.php b/src/TideWebformSubmissionListBuilder.php index 86bec6e..22ce9e2 100644 --- a/src/TideWebformSubmissionListBuilder.php +++ b/src/TideWebformSubmissionListBuilder.php @@ -2,6 +2,7 @@ namespace Drupal\tide_webform; +use Drupal\Core\Database\Database; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\webform\WebformSubmissionListBuilder; @@ -24,6 +25,11 @@ class TideWebformSubmissionListBuilder extends WebformSubmissionListBuilder { */ const STATE_UNPROCESSED = 'unprocessed'; + /** + * Submission state with_attachments. + */ + const STATE_WITH_ATTACHMENTS = 'with_attachments'; + /** * {@inheritdoc} */ @@ -48,6 +54,18 @@ protected function getQuery($keys = '', $state = '', $source_entity = '') { $query->condition('processed', 0); break; + case static::STATE_WITH_ATTACHMENTS: + $sub_query = Database::getConnection()->select('webform_submission_data', 'sd'); + $sub_query->join('file_usage', 'fu', 'fu.fid = CAST(sd.value as UNSIGNED)'); + $sub_query + ->fields('sd', ['sid']) + ->condition('sd.value', '', '<>') + ->groupBy('sd.sid'); + $query->condition( + $query->orConditionGroup() + ->condition('sid', $sub_query, 'IN') + ); + break; } return $query; } diff --git a/tide_webform.info.yml b/tide_webform.info.yml index 3919934..bfb611f 100644 --- a/tide_webform.info.yml +++ b/tide_webform.info.yml @@ -9,6 +9,8 @@ dependencies: - token_conditions:token_conditions - webform:webform - webform:webform_ui + - webform_rest:webform_rest + - restui:restui - dpc-sdp:tide_core config_devel: install: diff --git a/tide_webform.install b/tide_webform.install index 908aacb..c2b9a9b 100644 --- a/tide_webform.install +++ b/tide_webform.install @@ -325,3 +325,41 @@ function tide_webform_update_8013() { $config->save(); } } + +/** + * Updating webform settings for managed_file types. + */ +function tide_webform_update_8014() { + /** @var \Drupal\Core\Extension\ModuleHandler $moduleHandler */ + $moduleExists = \Drupal::service('module_handler')->moduleExists('webform_rest'); + // Check if module is both installed and enabled. + if (!$moduleExists) { + // If not, install the queue_mail module. + \Drupal::service('module_installer')->install(['webform_rest', 'restui']); + } + if (\Drupal::moduleHandler()->moduleExists('webform')) { + $webform_elements = [ + 'managed_file', + 'webform_element', + ]; + $config_factory = \Drupal::configFactory(); + $config = $config_factory->getEditable('webform.settings'); + $excluded_elements_values = $config->get('element.excluded_elements'); + foreach ($webform_elements as $webform_element) { + if (array_key_exists($webform_element, $excluded_elements_values)) { + unset($excluded_elements_values[$webform_element]); + } + } + $config->set('element.excluded_elements', $excluded_elements_values); + $config->set('file.default_max_filesize', '10 MB'); + $config->set('file.file_public', TRUE); + $config->set('file.default_managed_file_extensions', 'docx jpg png pdf csv zip xls mp3 mp4 wav avi'); + $config->save(); + } + module_load_include('inc', 'tide_core', 'includes/helpers'); + $config_storage = \Drupal::service('config.storage'); + $rest_resource_webform_file_upload = 'rest.resource.webform_rest_file_upload'; + $config_location = [drupal_get_path('module', 'tide_webform') . '/config/optional']; + $config_read = _tide_read_config($rest_resource_webform_file_upload, $config_location, TRUE); + $config_storage->write($rest_resource_webform_file_upload, $config_read); +} diff --git a/tide_webform.module b/tide_webform.module index e1560f1..6df3ace 100644 --- a/tide_webform.module +++ b/tide_webform.module @@ -39,12 +39,15 @@ function tide_webform_form_alter(&$form, FormStateInterface $form_state, $form_i if ($form_id == 'webform_ui_element_form') { $form['#after_build'][] = 'tide_webform_webform_ui_element_form_after_build'; + // Custom validation for the managed_file elemt type. + $form['#validate'][] = 'tide_webform_managed_file_type_element_validation'; } if ($form_id == 'webform_submission_filter_form') { $options = $form['filter']['state']['#options']; $options['processed'] = 'Exported [' . tide_webform_submission_filter_query(1) . ']'; $options['unprocessed'] = 'New [' . tide_webform_submission_filter_query(0) . ']'; + $options['with_attachments'] = 'With attachments [' . tide_webform_submission_data_filter() . ']'; $form['filter']['state']['#options'] = $options; } @@ -365,3 +368,64 @@ function tide_webform_form_webform_results_export_form_submit(array $form, FormS $options = ['query' => $query]; $form_state->setRedirect('entity.webform.results_export', $route_parameters, $options); } + +/** + * Custom validation callback for managed file type element. + * + * @param array $element + * The form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * Form state. + */ +function tide_webform_managed_file_type_element_validation(array $element, FormStateInterface $form_state) { + $allowed_file_formats = [ + 'docx', + 'jpg', + 'png', + 'pdf', + 'csv', + 'zip', + 'xls', + 'mp3', + 'mp4', + 'wav', + 'avi', + ]; + $element_settings = $form_state->getValues(); + if ($element_settings["properties"]["type"] !== "managed_file") { + return; + } + $given_file_formats = explode(" ", $element_settings["properties"]["file_extensions"]); + if ($element_settings["properties"]["multiple"] > 10 || $element_settings["properties"]["multiple"] === TRUE) { + $form_state->setError($element, t('Maximum allowed number of values are 10.')); + } + $matched_values = array_intersect($allowed_file_formats, $given_file_formats); + if (count($matched_values) > 0) { + $unmatched_values = array_diff($given_file_formats, $matched_values); + if (count($unmatched_values) > 0) { + $form_state->setError($element, t('Invalid file formats found: @format', ['@format' => implode(", ", $unmatched_values)])); + } + } + $unmatched_values = array_diff($allowed_file_formats, $matched_values); + if (count($matched_values) == 0 && count($unmatched_values) > 0) { + $form_state->setError($element, t('Invalid file formats found: @format', ['@format' => implode(", ", $given_file_formats)])); + } +} + +/** + * Function to build query for filter on webform submissions data pages. + * + * @return total + * Returns total from the webform submission data count. + */ +function tide_webform_submission_data_filter() { + $database = \Drupal::service('database'); + $select = $database->select('webform_submission_data', 'sd'); + $select->join('file_usage', 'fu', 'fu.fid = sd.value'); + $select + ->fields('sd', ['sid']) + ->condition('sd.value', '', '<>'); + $select->groupBy('sid'); + $total = $select->countQuery()->execute()->fetchField(); + return $total; +} diff --git a/tide_webform.services.yml b/tide_webform.services.yml index f639a16..993c7a5 100644 --- a/tide_webform.services.yml +++ b/tide_webform.services.yml @@ -4,4 +4,4 @@ services: public: false decorates: webform_submission.exporter decoration_priority: 4 - arguments: ['@tide_webform.exporter.inner', '@config.factory', '@file_system', '@entity_type.manager', '@stream_wrapper_manager', '@plugin.manager.archiver', '@plugin.manager.webform.element', '@plugin.manager.webform.exporter'] \ No newline at end of file + arguments: ['@tide_webform.exporter.inner', '@config.factory', '@file_system', '@entity_type.manager', '@stream_wrapper_manager', '@plugin.manager.archiver', '@plugin.manager.webform.element', '@plugin.manager.webform.exporter']