From aa3c71893e7aea98dff67e660df5f3b7832fafb0 Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 18 Oct 2022 16:10:19 -0300 Subject: [PATCH 01/37] delete media associated with an islandora object --- islandora.module | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/islandora.module b/islandora.module index 5b5446d13..708f8ec19 100644 --- a/islandora.module +++ b/islandora.module @@ -320,9 +320,10 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) 'media_extracted_text_add_form', 'media_file_add_form', 'media_image_add_form', 'media_fits_technical_metadata_add_form', 'media_video_add_form', ]; - + //kint($form); if (in_array($form['#form_id'], $media_add_forms)) { $params = \Drupal::request()->query->all(); + if (isset($params['edit'])) { $media_of_nid = $params['edit']['field_media_of']['widget'][0]['target_id']; $node = \Drupal::entityTypeManager()->getStorage('node')->load($media_of_nid); @@ -346,6 +347,7 @@ function islandora_field_widget_image_image_form_alter(&$element, $form_state, $ function islandora_add_default_image_alt_text($element, $form_state, $form) { if ($element['alt']['#access']) { $params = \Drupal::request()->query->all(); + if (isset($params['edit'])) { $media_of_nid = $params['edit']['field_media_of']['widget'][0]['target_id']; $node = \Drupal::entityTypeManager()->getStorage('node')->load($media_of_nid); @@ -423,7 +425,7 @@ function islandora_entity_extra_field_info() { if (!empty($pseudo_bundles)) { foreach ($pseudo_bundles as $key) { [$bundle, $content_entity] = explode(":", $key); - $extra_field[$content_entity][$bundle]['display'][IslandoraSettingsForm::GEMINI_PSEUDO_FIELD] = [ + $extra_field[$content_entity][$bundle]['display']['field_gemini_uri'] = [ 'label' => t('Fedora URI'), 'description' => t('The URI to the persistent'), 'weight' => 100, @@ -548,3 +550,27 @@ function islandora_preprocess_views_view_table(&$variables) { } } } + +function islandora_form_node_islandora_object_delete_form_alter(&$form, &$form_state){ + $form['delete_associated_content'] = array( + '#type' => 'checkbox', + '#title' => t('Delete all associated medias and nodes'), + ); + + $form['actions']['submit']['#submit'][] = 'islandora_form_node_islandora_object_delete_form_submit'; + return $form; +} + +function islandora_form_node_islandora_object_delete_form_submit($form, &$form_state){ + + $result = $form_state->getValues('delete_associated_content'); + + if($result['delete_associated_content'] == 1) { + $utils = \Drupal::service('islandora.utils'); + $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); + foreach ($medias as $media) { + $media->delete(); + } + } +} + From 33ce9e4e135dacc342819b0b8bea2824cd023c72 Mon Sep 17 00:00:00 2001 From: shriram Date: Thu, 27 Oct 2022 14:31:18 -0300 Subject: [PATCH 02/37] list media associated with a Islandora object --- islandora.module | 69 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/islandora.module b/islandora.module index 708f8ec19..ab9eab18a 100644 --- a/islandora.module +++ b/islandora.module @@ -27,6 +27,7 @@ use Drupal\file\FileInterface; use Drupal\taxonomy\TermInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\serialization\Normalizer\CacheableNormalizerInterface; +use Drupal\Core\Entity\EntityForm; /** * Implements hook_help(). @@ -320,7 +321,7 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) 'media_extracted_text_add_form', 'media_file_add_form', 'media_image_add_form', 'media_fits_technical_metadata_add_form', 'media_video_add_form', ]; - //kint($form); + if (in_array($form['#form_id'], $media_add_forms)) { $params = \Drupal::request()->query->all(); @@ -332,6 +333,51 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) } } } + + $form_object = $form_state->getFormObject(); + + $utils = \Drupal::service('islandora.utils'); + +// kint($form,$form_state); + + if($form_object instanceof EntityForm) { + $entity = $form_object->getEntity(); + if ($utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { + $form['delete_associated_content'] = array( + '#type' => 'checkbox', + '#title' => t('Delete all associated medias and nodes'), + ); + + $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); + $media_list = ""; + + foreach($medias as $media){ + $media_list.= "
  • {$media->getName()}
  • "; + } + + $form['media_items'] = array( + '#suffix' => "", // Add markup after form item + ); + + $form['actions']['submit']['#submit'][] = 'islandora_object_delete_form_submit'; + return $form; + } + } + return $form; +} + +function islandora_object_delete_form_submit($form, &$form_state){ + + $result = $form_state->getValues('delete_associated_content'); + $utils = \Drupal::service('islandora.utils'); + + if($result['delete_associated_content'] == 1) { + + $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); + foreach ($medias as $media) { + $media->delete(); + } + } } /** @@ -551,26 +597,5 @@ function islandora_preprocess_views_view_table(&$variables) { } } -function islandora_form_node_islandora_object_delete_form_alter(&$form, &$form_state){ - $form['delete_associated_content'] = array( - '#type' => 'checkbox', - '#title' => t('Delete all associated medias and nodes'), - ); - - $form['actions']['submit']['#submit'][] = 'islandora_form_node_islandora_object_delete_form_submit'; - return $form; -} -function islandora_form_node_islandora_object_delete_form_submit($form, &$form_state){ - - $result = $form_state->getValues('delete_associated_content'); - - if($result['delete_associated_content'] == 1) { - $utils = \Drupal::service('islandora.utils'); - $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); - foreach ($medias as $media) { - $media->delete(); - } - } -} From 3602bb441b991dce7a08cffb98b93300b05ea907 Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 1 Nov 2022 12:16:29 -0300 Subject: [PATCH 03/37] fixed failing coding standard checks --- islandora.module | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/islandora.module b/islandora.module index ab9eab18a..63018266e 100644 --- a/islandora.module +++ b/islandora.module @@ -324,7 +324,6 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) if (in_array($form['#form_id'], $media_add_forms)) { $params = \Drupal::request()->query->all(); - if (isset($params['edit'])) { $media_of_nid = $params['edit']['field_media_of']['widget'][0]['target_id']; $node = \Drupal::entityTypeManager()->getStorage('node')->load($media_of_nid); @@ -333,31 +332,28 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) } } } - $form_object = $form_state->getFormObject(); $utils = \Drupal::service('islandora.utils'); -// kint($form,$form_state); - - if($form_object instanceof EntityForm) { + if ($form_object instanceof EntityForm) { $entity = $form_object->getEntity(); if ($utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { - $form['delete_associated_content'] = array( + $form['delete_associated_content'] = [ '#type' => 'checkbox', '#title' => t('Delete all associated medias and nodes'), - ); + ]; $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); $media_list = ""; - foreach($medias as $media){ - $media_list.= "
  • {$media->getName()}
  • "; + foreach ($medias as $media) { + $media_list .= "
  • {$media->getName()}
  • "; } - $form['media_items'] = array( - '#suffix' => "
      {$media_list}
    ", // Add markup after form item - ); + $form['media_items'] = [ + '#suffix' => "
      {$media_list}
    ", + ]; $form['actions']['submit']['#submit'][] = 'islandora_object_delete_form_submit'; return $form; @@ -366,12 +362,15 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) return $form; } -function islandora_object_delete_form_submit($form, &$form_state){ +/** + * Implements a submit handler for the delete form. + */ +function islandora_object_delete_form_submit($form, &$form_state) { $result = $form_state->getValues('delete_associated_content'); $utils = \Drupal::service('islandora.utils'); - if($result['delete_associated_content'] == 1) { + if ($result['delete_associated_content'] == 1) { $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); foreach ($medias as $media) { @@ -393,7 +392,6 @@ function islandora_field_widget_image_image_form_alter(&$element, $form_state, $ function islandora_add_default_image_alt_text($element, $form_state, $form) { if ($element['alt']['#access']) { $params = \Drupal::request()->query->all(); - if (isset($params['edit'])) { $media_of_nid = $params['edit']['field_media_of']['widget'][0]['target_id']; $node = \Drupal::entityTypeManager()->getStorage('node')->load($media_of_nid); @@ -471,7 +469,7 @@ function islandora_entity_extra_field_info() { if (!empty($pseudo_bundles)) { foreach ($pseudo_bundles as $key) { [$bundle, $content_entity] = explode(":", $key); - $extra_field[$content_entity][$bundle]['display']['field_gemini_uri'] = [ + $extra_field[$content_entity][$bundle]['display'][IslandoraSettingsForm::GEMINI_PSEUDO_FIELD] = [ 'label' => t('Fedora URI'), 'description' => t('The URI to the persistent'), 'weight' => 100, @@ -596,6 +594,3 @@ function islandora_preprocess_views_view_table(&$variables) { } } } - - - From 5bd2cdd85177397c23f4f7e3b639469597b5c9cb Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 1 Nov 2022 13:08:36 -0300 Subject: [PATCH 04/37] check if the entity is a node --- islandora.module | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/islandora.module b/islandora.module index 63018266e..e8aeb2322 100644 --- a/islandora.module +++ b/islandora.module @@ -333,12 +333,11 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) } } $form_object = $form_state->getFormObject(); - $utils = \Drupal::service('islandora.utils'); if ($form_object instanceof EntityForm) { $entity = $form_object->getEntity(); - if ($utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { + if ($entity->getEntityTypeId() == "node" && $utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { $form['delete_associated_content'] = [ '#type' => 'checkbox', '#title' => t('Delete all associated medias and nodes'), From fd5c38a10734efc26de0b3634c8c08a5791f8e36 Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 1 Nov 2022 16:00:22 -0300 Subject: [PATCH 05/37] added test cases for deleting node with media --- tests/src/Functional/DeleteNodeWithMedia.php | 94 ++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/src/Functional/DeleteNodeWithMedia.php diff --git a/tests/src/Functional/DeleteNodeWithMedia.php b/tests/src/Functional/DeleteNodeWithMedia.php new file mode 100644 index 000000000..b9cc8f99a --- /dev/null +++ b/tests/src/Functional/DeleteNodeWithMedia.php @@ -0,0 +1,94 @@ +drupalCreateUser([ + 'delete any media', + 'create media', + 'view media', + 'bypass node access', + ]); + $this->drupalLogin($account); + + $assert_session = $this->assertSession(); + + $testImageMediaType = $this->createMediaType('image', ['id' => 'test_image_media_type']); + $testImageMediaType->save(); + + $this->createEntityReferenceField('media', $testImageMediaType->id(), 'field_media_of', 'Media Of', 'node', 'default', [], 2); + + $node = $this->container->get('entity_type.manager')->getStorage('node')->create([ + 'type' => 'test_type', + 'title' => 'node', + ]); + $node->save(); + + // Make an image for the Media. + $file = $this->container->get('entity_type.manager')->getStorage('file')->create([ + 'uid' => $account->id(), + 'uri' => "public://test.jpeg", + 'filename' => "test.jpeg", + 'filemime' => "image/jpeg", + 'status' => FILE_STATUS_PERMANENT, + ]); + $file->save(); + + $this->drupalGet("node/1/delete"); + $assert_session->pageTextNotContains('Delete all associated medias and nodes'); + + // Make the media, and associate it with the image and node. + $media1 = $this->container->get('entity_type.manager')->getStorage('media')->create([ + 'bundle' => $testImageMediaType->id(), + 'name' => 'Media1', + 'field_media_image' => + [ + 'target_id' => $file->id(), + 'alt' => 'Some Alt', + 'title' => 'Some Title', + ], + 'field_media_of' => ['target_id' => $node->id()], + ]); + $media1->save(); + + $media2 = $this->container->get('entity_type.manager')->getStorage('media')->create([ + 'bundle' => $testImageMediaType->id(), + 'name' => 'Media2', + 'field_media_image' => + [ + 'target_id' => $file->id(), + 'alt' => 'Some Alt', + 'title' => 'Some Title', + ], + 'field_media_of' => ['target_id' => $node->id()], + ]); + $media2->save(); + + $delete = ['delete_associated_content' => TRUE]; + + $this->drupalGet("node/1/delete"); + $assert_session->pageTextContains('Media1'); + $assert_session->pageTextContains('Media2'); + $this->submitForm($delete, 'Delete'); + + $assert_session->pageTextContains('Media1'); + $assert_session->pageTextContains('Media2'); + + $this->drupalGet("media/1/delete"); + $assert_session->pageTextContains('Page not found'); + + $this->drupalGet("media/2/delete"); + $assert_session->pageTextContains('Page not found'); + } + +} From e3c7e6eddac3f81614f923c96463f8d24e250412 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Sat, 23 Jul 2022 14:43:48 -0300 Subject: [PATCH 06/37] Document the add members and add media pages. --- src/Controller/ManageMediaController.php | 9 ++++++++- src/Controller/ManageMembersController.php | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Controller/ManageMediaController.php b/src/Controller/ManageMediaController.php index bd670561a..a58d98607 100644 --- a/src/Controller/ManageMediaController.php +++ b/src/Controller/ManageMediaController.php @@ -25,7 +25,7 @@ class ManageMediaController extends ManageMembersController { public function addToNodePage(NodeInterface $node) { $field = IslandoraUtils::MEDIA_OF_FIELD; - return $this->generateTypeList( + $add_media_list = $this->generateTypeList( 'media', 'media_type', 'entity.media.add_form', @@ -33,6 +33,13 @@ public function addToNodePage(NodeInterface $node) { $field, ['query' => ["edit[$field][widget][0][target_id]" => $node->id()]] ); + + return [ + '#type' => 'markup', + '#markup' => $this->t("These available media types below have @field and it is configured to allow this content type.", + ['@field' => $field]), + 'add_media' => $add_media_list, + ]; } /** diff --git a/src/Controller/ManageMembersController.php b/src/Controller/ManageMembersController.php index 7f480fb3d..e07ec5dfb 100644 --- a/src/Controller/ManageMembersController.php +++ b/src/Controller/ManageMembersController.php @@ -88,7 +88,8 @@ public static function create(ContainerInterface $container) { */ public function addToNodePage(NodeInterface $node) { $field = IslandoraUtils::MEMBER_OF_FIELD; - return $this->generateTypeList( + + $add_node_list = $this->generateTypeList( 'node', 'node_type', 'node.add', @@ -96,6 +97,13 @@ public function addToNodePage(NodeInterface $node) { $field, ['query' => ["edit[$field][widget][0][target_id]" => $node->id()]] ); + + return [ + '#type' => 'markup', + '#markup' => $this->t("These available content types below have @field and it is configured to allow this content type.", + ['@field' => $field]), + 'add_node' => $add_node_list, + ]; } /** From 7eebb65c2b7c1f79fdfa563302836c97520176e4 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Mon, 7 Nov 2022 17:10:30 -0400 Subject: [PATCH 07/37] Clarify wording and add manage link. --- src/Controller/ManageMediaController.php | 7 +++++-- src/Controller/ManageMembersController.php | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Controller/ManageMediaController.php b/src/Controller/ManageMediaController.php index a58d98607..d15175f96 100644 --- a/src/Controller/ManageMediaController.php +++ b/src/Controller/ManageMediaController.php @@ -36,8 +36,11 @@ public function addToNodePage(NodeInterface $node) { return [ '#type' => 'markup', - '#markup' => $this->t("These available media types below have @field and it is configured to allow this content type.", - ['@field' => $field]), + '#markup' => $this->t("The following media types can be added because they have the @field field. Manage media types.", + [ + '@field' => $field, + '@manage_media_page' => '/admin/structure/media', + ]), 'add_media' => $add_media_list, ]; } diff --git a/src/Controller/ManageMembersController.php b/src/Controller/ManageMembersController.php index e07ec5dfb..bfd2cf74f 100644 --- a/src/Controller/ManageMembersController.php +++ b/src/Controller/ManageMembersController.php @@ -100,8 +100,11 @@ public function addToNodePage(NodeInterface $node) { return [ '#type' => 'markup', - '#markup' => $this->t("These available content types below have @field and it is configured to allow this content type.", - ['@field' => $field]), + '#markup' => $this->t("The following content types can be added because they have the @field field. Manage content types.", + [ + '@field' => $field, + '@manage_content_types' => '/admin/structure/types', + ]), 'add_node' => $add_node_list, ]; } From 386ba0ceb19e71119cb9e035381f4c93857560e1 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Mon, 7 Nov 2022 18:36:10 -0400 Subject: [PATCH 08/37] Detect access before showing manage links. --- src/Controller/ManageMediaController.php | 16 +++++++++++----- src/Controller/ManageMembersController.php | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/Controller/ManageMediaController.php b/src/Controller/ManageMediaController.php index d15175f96..025d1d9dc 100644 --- a/src/Controller/ManageMediaController.php +++ b/src/Controller/ManageMediaController.php @@ -6,6 +6,7 @@ use Drupal\Core\Access\AccessResult; use Drupal\Core\Routing\RouteMatch; use Drupal\node\Entity\Node; +use Drupal\Core\Url; use Drupal\node\NodeInterface; /** @@ -34,13 +35,18 @@ public function addToNodePage(NodeInterface $node) { ['query' => ["edit[$field][widget][0][target_id]" => $node->id()]] ); + $manage_link = Url::fromRoute('entity.media_type.collection')->toRenderArray(); + $manage_link['#title'] = $this->t('Manage media types'); + $manage_link['#type'] = 'link'; + $manage_link['#prefix'] = ' '; + $manage_link['#suffix'] = '.'; + return [ '#type' => 'markup', - '#markup' => $this->t("The following media types can be added because they have the @field field. Manage media types.", - [ - '@field' => $field, - '@manage_media_page' => '/admin/structure/media', - ]), + '#markup' => $this->t("The following media types can be added because they have the @field field.", [ + '@field' => $field, + ]), + 'manage_link' => $manage_link, 'add_media' => $add_media_list, ]; } diff --git a/src/Controller/ManageMembersController.php b/src/Controller/ManageMembersController.php index bfd2cf74f..9827ff350 100644 --- a/src/Controller/ManageMembersController.php +++ b/src/Controller/ManageMembersController.php @@ -7,6 +7,7 @@ use Drupal\Core\Entity\Controller\EntityController; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Link; +use Drupal\Core\Url; use Drupal\islandora\IslandoraUtils; use Drupal\node\NodeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -98,13 +99,18 @@ public function addToNodePage(NodeInterface $node) { ['query' => ["edit[$field][widget][0][target_id]" => $node->id()]] ); + $manage_link = Url::fromRoute('entity.node_type.collection')->toRenderArray(); + $manage_link['#title'] = $this->t('Manage content types'); + $manage_link['#type'] = 'link'; + $manage_link['#prefix'] = ' '; + $manage_link['#suffix'] = '.'; + return [ '#type' => 'markup', - '#markup' => $this->t("The following content types can be added because they have the @field field. Manage content types.", - [ - '@field' => $field, - '@manage_content_types' => '/admin/structure/types', - ]), + '#markup' => $this->t("The following content types can be added because they have the @field field.", [ + '@field' => $field, + ]), + 'manage_link' => $manage_link, 'add_node' => $add_node_list, ]; } From 7ef1afffa2c814b83decb86e13677ecde764d68f Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 8 Nov 2022 13:44:38 -0400 Subject: [PATCH 09/37] delete media with files and translations --- islandora.module | 159 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 18 deletions(-) diff --git a/islandora.module b/islandora.module index e8aeb2322..9130caebe 100644 --- a/islandora.module +++ b/islandora.module @@ -28,6 +28,7 @@ use Drupal\taxonomy\TermInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\serialization\Normalizer\CacheableNormalizerInterface; use Drupal\Core\Entity\EntityForm; +use Drupal\file\Entity\File; /** * Implements hook_help(). @@ -337,25 +338,34 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) if ($form_object instanceof EntityForm) { $entity = $form_object->getEntity(); - if ($entity->getEntityTypeId() == "node" && $utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { - $form['delete_associated_content'] = [ - '#type' => 'checkbox', - '#title' => t('Delete all associated medias and nodes'), - ]; + if ($entity->getEntityTypeId() == "node" && $utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); - $media_list = ""; + if (count($medias) != 0) { + $form['delete_associated_content'] = [ + '#type' => 'checkbox', + '#title' => t('Delete all associated medias and nodes'), + ]; + + foreach ($medias as $media) { + $media_list[] = $media->getName(); + } + $form['media_items'] = [ + '#theme' => 'item_list', + '#type' => 'ul', + '#items' => $media_list, + '#attributes' => ['class' => 'mylist'], + '#wrapper_attributes' => ['class' => 'container'], + '#attached' => [ + 'library' => [ + 'islandora/drupal.islandora.theme_css', + ], + ], + ]; - foreach ($medias as $media) { - $media_list .= "
  • {$media->getName()}
  • "; + $form['actions']['submit']['#submit'][] = 'islandora_object_delete_form_submit'; + return $form; } - - $form['media_items'] = [ - '#suffix' => "
      {$media_list}
    ", - ]; - - $form['actions']['submit']['#submit'][] = 'islandora_object_delete_form_submit'; - return $form; } } return $form; @@ -371,10 +381,123 @@ function islandora_object_delete_form_submit($form, &$form_state) { if ($result['delete_associated_content'] == 1) { - $medias = $utils->getMedia($form_state->getFormObject()->getEntity()); - foreach ($medias as $media) { - $media->delete(); + $node = $form_state->getFormObject()->getEntity(); + $medias = $utils->getMedia($node); + $media_list = ""; + + $entity_type_manager = \Drupal::entityTypeManager(); + $entity_field_manager = \Drupal::service('entity_field.manager'); + $current_user = \Drupal::currentUser(); + $logger = \Drupal::logger('logger.channel.islandora'); + $messenger = \Drupal::messenger(); + + $total_count = 0; + $delete_media = []; + $delete_media_translations = []; + $delete_files = []; + $inaccessible_entities = []; + $media_storage = $entity_type_manager->getStorage('media'); + $file_storage = $entity_type_manager->getStorage('file'); + + foreach ($medias as $id => $media) { + $media_list .= $id . ", "; + $lang = $media->language()->getId(); + $selected_langcodes[$lang] = $lang; + + if (!$media->access('delete', $current_user)) { + $inaccessible_entities[] = $media; + continue; + } + // Check for files. + $fields = $entity_field_manager->getFieldDefinitions('media', $media->bundle()); + foreach ($fields as $field) { + $type = $field->getType(); + if ($type == 'file' || $type == 'image') { + $target_id = $media->get($field->getName())->target_id; + $file = File::load($target_id); + if ($file) { + if (!$file->access('delete', $current_user)) { + $inaccessible_entities[] = $file; + continue; + } + $delete_files[$file->id()] = $file; + $total_count++; + } + } + } + + foreach ($selected_langcodes as $langcode) { + // We're only working with media, which are translatable. + $entity = $media->getTranslation($langcode); + if ($entity->isDefaultTranslation()) { + $delete_media[$id] = $entity; + unset($delete_media_translations[$id]); + $total_count += count($entity->getTranslationLanguages()); + } + elseif (!isset($delete_media[$id])) { + $delete_media_translations[$id][] = $entity; + } + } } + + if ($delete_media) { + $media_storage->delete($delete_media); + foreach ($delete_media as $media) { + $logger->notice('The media %label has been deleted.', [ + '%label' => $media->label(), + ]); + } + } + + if ($delete_files) { + $file_storage->delete($delete_files); + foreach ($delete_files as $media) { + $logger->notice('The file %label has been deleted.', [ + '%label' => $media->label(), + ]); + } + } + + if ($delete_media_translations) { + foreach ($delete_media_translations as $id => $translations) { + $media = $medias[$id]; + foreach ($translations as $translation) { + $media->removeTranslation($translation->language()->getId()); + } + $media->save(); + foreach ($translations as $translation) { + $logger->notice('The media %label @language translation has been deleted', [ + '%label' => $media->label(), + '@language' => $translation->language()->getName(), + ]); + } + $total_count += count($translations); + } + } + + if ($inaccessible_entities) { + $messenger->addWarning("@count items has not been deleted because you do not have the necessary permissions.", [ + '@count' => count($inaccessible_entities), + ]); + } + + $build = [ + 'heading' => [ + '#type' => 'html_tag', + '#tag' => 'div', + '#value' => t("The repository item @node and @media", [ + '@node' => $node->getTitle(), + '@media' => \Drupal::translation()->formatPlural( + substr_count($media_list, ",") + 1, 'the media with the id @media has been deleted.', + 'the medias with the id @media have been deleted.', + ['@media' => mb_substr($media_list, 0, strlen($media_list) - 2)]), + ]), + ], + ]; + + $message = \Drupal::service('renderer')->renderPlain($build); + $messenger->deleteByType('status'); + $messenger->addStatus($message); } } From ef1f36f2836bcdc82a8b2ca1526924b99a54f70c Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 8 Nov 2022 16:07:27 -0400 Subject: [PATCH 10/37] Updated test cases to include file deletion --- islandora.module | 9 ++++++--- ...WithMedia.php => DeleteNodeWithMediaAndFile.php} | 13 +++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) rename tests/src/Functional/{DeleteNodeWithMedia.php => DeleteNodeWithMediaAndFile.php} (87%) diff --git a/islandora.module b/islandora.module index 9130caebe..44dc35a7d 100644 --- a/islandora.module +++ b/islandora.module @@ -347,9 +347,12 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) '#title' => t('Delete all associated medias and nodes'), ]; - foreach ($medias as $media) { + $media_list = []; + + foreach ($medias as $media) { $media_list[] = $media->getName(); } + $form['media_items'] = [ '#theme' => 'item_list', '#type' => 'ul', @@ -451,9 +454,9 @@ function islandora_object_delete_form_submit($form, &$form_state) { if ($delete_files) { $file_storage->delete($delete_files); - foreach ($delete_files as $media) { + foreach ($delete_files as $file) { $logger->notice('The file %label has been deleted.', [ - '%label' => $media->label(), + '%label' => $file->label(), ]); } } diff --git a/tests/src/Functional/DeleteNodeWithMedia.php b/tests/src/Functional/DeleteNodeWithMediaAndFile.php similarity index 87% rename from tests/src/Functional/DeleteNodeWithMedia.php rename to tests/src/Functional/DeleteNodeWithMediaAndFile.php index b9cc8f99a..ff793f0da 100644 --- a/tests/src/Functional/DeleteNodeWithMedia.php +++ b/tests/src/Functional/DeleteNodeWithMediaAndFile.php @@ -7,17 +7,18 @@ * * @group islandora */ -class DeleteNodeWithMedia extends IslandoraFunctionalTestBase { +class DeleteNodeWithMediaAndFile extends IslandoraFunctionalTestBase { /** * Tests delete Node and its assoicated media. */ - public function testDeleteNodeWithMedia() { + public function testDeleteNodeWithMediaAndFile() { $account = $this->drupalCreateUser([ 'delete any media', 'create media', 'view media', 'bypass node access', + 'access files overview', ]); $this->drupalLogin($account); @@ -81,14 +82,18 @@ public function testDeleteNodeWithMedia() { $assert_session->pageTextContains('Media2'); $this->submitForm($delete, 'Delete'); - $assert_session->pageTextContains('Media1'); - $assert_session->pageTextContains('Media2'); + $assert_session->pageTextContains($media1->id()); + $assert_session->pageTextContains($media2->id()); $this->drupalGet("media/1/delete"); $assert_session->pageTextContains('Page not found'); $this->drupalGet("media/2/delete"); $assert_session->pageTextContains('Page not found'); + + $this->drupalGet("/admin/content/files"); + $assert_session->pageTextNotContains('test.jpeg'); + } } From 9b58fc9ecbd2e79cfa04be6ff12e5551931ff9bb Mon Sep 17 00:00:00 2001 From: shriram Date: Thu, 10 Nov 2022 14:56:58 -0400 Subject: [PATCH 11/37] added islandora.libraries.yml --- css/islandora.theme.css | 3 +++ islandora.libraries.yml | 5 +++++ islandora.module | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 css/islandora.theme.css create mode 100644 islandora.libraries.yml diff --git a/css/islandora.theme.css b/css/islandora.theme.css new file mode 100644 index 000000000..696587ac1 --- /dev/null +++ b/css/islandora.theme.css @@ -0,0 +1,3 @@ +.container .islandora-media-items { + margin: 0; +} diff --git a/islandora.libraries.yml b/islandora.libraries.yml new file mode 100644 index 000000000..047006bfe --- /dev/null +++ b/islandora.libraries.yml @@ -0,0 +1,5 @@ +drupal.islandora.theme_css: + version: VERSION + css: + theme: + css/islandora.theme.css: {} diff --git a/islandora.module b/islandora.module index 44dc35a7d..66c74ad54 100644 --- a/islandora.module +++ b/islandora.module @@ -357,8 +357,8 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) '#theme' => 'item_list', '#type' => 'ul', '#items' => $media_list, - '#attributes' => ['class' => 'mylist'], - '#wrapper_attributes' => ['class' => 'container'], + '#attributes' => ['class' => ['islandora-media-items']], + '#wrapper_attributes' => ['class' => ['container']], '#attached' => [ 'library' => [ 'islandora/drupal.islandora.theme_css', From 5c24c190184b680914f10bae7fbff23fa33663bb Mon Sep 17 00:00:00 2001 From: shriram Date: Tue, 15 Nov 2022 14:35:01 -0400 Subject: [PATCH 12/37] added feature toggle for the behavior --- islandora.module | 4 +++- src/Form/IslandoraSettingsForm.php | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/islandora.module b/islandora.module index 66c74ad54..5cab2ccee 100644 --- a/islandora.module +++ b/islandora.module @@ -333,10 +333,12 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) } } } + $form_object = $form_state->getFormObject(); $utils = \Drupal::service('islandora.utils'); + $config = \Drupal::config('islandora.settings')->get('delete_media_and_files'); - if ($form_object instanceof EntityForm) { + if ($config == 1 && $form_object instanceof EntityForm) { $entity = $form_object->getEntity(); if ($entity->getEntityTypeId() == "node" && $utils->isIslandoraType($entity->getEntityTypeId(), $entity->bundle()) && strpos($form['#form_id'], 'delete_form') !== FALSE) { diff --git a/src/Form/IslandoraSettingsForm.php b/src/Form/IslandoraSettingsForm.php index 5049ef161..a65ab82f0 100644 --- a/src/Form/IslandoraSettingsForm.php +++ b/src/Form/IslandoraSettingsForm.php @@ -42,6 +42,7 @@ class IslandoraSettingsForm extends ConfigFormBase { 'year', ]; const GEMINI_PSEUDO_FIELD = 'field_gemini_uri'; + const NODE_DELETE_MEDIA_AND_FILES = 'delete_media_and_files'; /** * To list the available bundle types. @@ -201,6 +202,14 @@ public function buildForm(array $form, FormStateInterface $form_state) { $fedora_url = NULL; } + $form[self::NODE_DELETE_MEDIA_AND_FILES] = [ + '#type' => 'checkbox', + '#title' => $this->t('Node Delete with Media and Files'), + '#description' => $this->t('adds a checkbox in the "Delete" tab of islandora objects to delete media and files associated with the object.' + ), + '#default_value' => (bool) $config->get(self::NODE_DELETE_MEDIA_AND_FILES), + ]; + $form[self::FEDORA_URL] = [ '#type' => 'textfield', '#title' => $this->t('Fedora URL'), @@ -351,6 +360,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ->set(self::UPLOAD_FORM_LOCATION, $form_state->getValue(self::UPLOAD_FORM_LOCATION)) ->set(self::UPLOAD_FORM_ALLOWED_MIMETYPES, $form_state->getValue(self::UPLOAD_FORM_ALLOWED_MIMETYPES)) ->set(self::GEMINI_PSEUDO, $new_pseudo_types) + ->set(self::NODE_DELETE_MEDIA_AND_FILES, $form_state->getValue(self::NODE_DELETE_MEDIA_AND_FILES)) ->save(); parent::submitForm($form, $form_state); From b0c43accb83d54402cf8989232f839fb66addc0f Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Mon, 21 Nov 2022 12:20:20 -0400 Subject: [PATCH 13/37] Upgrade the EVA to 3.0. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c02d7c168..eebdd9ab7 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "drupal/jwt": "^1.0.0-beta5", "drupal/filehash": "^1.1 || ^2", "drupal/prepopulate" : "^2.2", - "drupal/eva" : "^2.0", + "drupal/eva" : "^3.0", "drupal/features" : "^3.7", "drupal/migrate_plus" : "^5.1", "drupal/migrate_source_csv" : "^3.4", From 4bed36dedeac2d7c05566ef0dde1a579987addd2 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Mon, 25 Jul 2022 13:43:30 -0300 Subject: [PATCH 14/37] Revert "Allowing Image fields for multi-file media (#860)" This reverts commit a297796f47b23b9f5a778d65fe6bee110a70d6ef. --- src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php b/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php index be9eca80b..54e7bde0c 100644 --- a/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php +++ b/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php @@ -88,16 +88,10 @@ protected function generateData(EntityInterface $entity) { */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $form = parent::buildConfigurationForm($form, $form_state); - $map = $this->entityFieldManager->getFieldMapByFieldType('file'); $file_fields = $map['media']; $file_options = array_combine(array_keys($file_fields), array_keys($file_fields)); - - $map = $this->entityFieldManager->getFieldMapByFieldType('image'); - $image_fields = $map['media']; - $image_options = array_combine(array_keys($image_fields), array_keys($image_fields)); - - $file_options = array_merge(['' => ''], $file_options, $image_options); + $file_options = array_merge(['' => ''], $file_options); $form['event']['#disabled'] = 'disabled'; $form['destination_field_name'] = [ From 72eaaf659adf8e0a8a27a1c18f0a6b9729db34e0 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Tue, 26 Jul 2022 13:31:22 -0300 Subject: [PATCH 15/37] Add Image fields only to Image derivative code. Co-authored-by: @ajstanley --- .../Action/GenerateImageDerivativeFile.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php index d6f99b584..54b215f38 100644 --- a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php +++ b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php @@ -34,7 +34,23 @@ public function defaultConfiguration() { */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $form = parent::buildConfigurationForm($form, $form_state); - $form['mimetype']['#description'] = $this->t('Mimetype to convert to (e.g. application/xml, etc...)'); + $map = $this->entityFieldManager->getFieldMapByFieldType('image'); + $file_fields = $map['media']; + $file_options = array_combine(array_keys($file_fields), array_keys($file_fields)); + $file_options = array_merge(['' => ''], $file_options); + // @todo figure out how to write to thumbnail, which is not a real field. + // see https://github.com/Islandora/islandora/issues/891. + unset($file_options['thumbnail']); + + $form['destination_field_name'] = [ + '#required' => TRUE, + '#type' => 'select', + '#options' => $file_options, + '#title' => $this->t('Destination Image field Name'), + '#default_value' => $this->configuration['destination_field_name'], + '#description' => $this->t('Image field on Media to hold derivative. Cannot be the same as source'), + ]; + $form['mimetype']['#value'] = 'image/jpeg'; $form['mimetype']['#type'] = 'hidden'; return $form; From 74dcfd0fa4a321f7007f8f464c37eee4d9f5c85d Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Thu, 24 Nov 2022 19:50:10 -0400 Subject: [PATCH 16/37] Improve wording on multi-file derivative Action forms. --- .../Action/GenerateImageDerivativeFile.php | 17 +++++++++---- src/Controller/MediaSourceController.php | 3 +-- src/MediaSource/MediaSourceService.php | 4 +-- .../AbstractGenerateDerivativeMediaFile.php | 25 ++++++++++++++++--- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php index 54b215f38..e0420fe8f 100644 --- a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php +++ b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php @@ -6,7 +6,10 @@ use Drupal\islandora\Plugin\Action\AbstractGenerateDerivativeMediaFile; /** - * Emits a Node for generating derivatives event. + * Emits a Media for generating derivatives event. + * + * Attaches the result as a file in an image field on the emitting + * Media ("multi-file media"). * * @Action( * id = "generate_image_derivative_file", @@ -24,7 +27,6 @@ public function defaultConfiguration() { $config['path'] = '[date:custom:Y]-[date:custom:m]/[media:mid]-ImageService.jpg'; $config['mimetype'] = 'application/xml'; $config['queue'] = 'islandora-connector-houdini'; - $config['destination_media_type'] = 'file'; $config['scheme'] = $this->config->get('default_scheme'); return $config; } @@ -46,13 +48,18 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#required' => TRUE, '#type' => 'select', '#options' => $file_options, - '#title' => $this->t('Destination Image field Name'), + '#title' => $this->t('Destination Image field'), '#default_value' => $this->configuration['destination_field_name'], - '#description' => $this->t('Image field on Media to hold derivative. Cannot be the same as source'), + '#description' => $this->t('This Action stores the derivative in an + Image field. If you need to store the result in a File field, use + "Generate a Derivative File for Media Attachment". Selected target field + must be an additional field, not the media\'s main storage field. + Selected target field must be present on the media.'), ]; $form['mimetype']['#value'] = 'image/jpeg'; - $form['mimetype']['#type'] = 'hidden'; + $form['mimetype']['#description'] = 'Mimetype to convert to. Must be + compatible with the destination image field.'; return $form; } diff --git a/src/Controller/MediaSourceController.php b/src/Controller/MediaSourceController.php index bab43fcfc..3d0e79092 100644 --- a/src/Controller/MediaSourceController.php +++ b/src/Controller/MediaSourceController.php @@ -280,8 +280,7 @@ public function attachToMedia( */ public function attachToMediaAccess(AccountInterface $account, RouteMatch $route_match) { $media = $route_match->getParameter('media'); - $node = $this->utils->getParentNode($media); - return AccessResult::allowedIf($node->access('update', $account) && $account->hasPermission('create media')); + return AccessResult::allowedIf($media->access('update', $account)); } } diff --git a/src/MediaSource/MediaSourceService.php b/src/MediaSource/MediaSourceService.php index 9399e3343..60e41672c 100644 --- a/src/MediaSource/MediaSourceService.php +++ b/src/MediaSource/MediaSourceService.php @@ -268,8 +268,8 @@ public function putToNode( 'uri' => $content_location, 'filename' => $this->fileSystem->basename($content_location), 'filemime' => $mimetype, - 'status' => FILE_STATUS_PERMANENT, ]); + $file->setPermanent(); // Validate file extension. $source_field_config = $this->entityTypeManager->getStorage('field_config')->load("media.$bundle.$source_field"); @@ -349,8 +349,8 @@ public function putToMedia( 'uri' => $content_location, 'filename' => $this->fileSystem->basename($content_location), 'filemime' => $mimetype, - 'status' => FILE_STATUS_PERMANENT, ]); + $file->setPermanent(); // Validate file extension. $bundle = $media->bundle(); diff --git a/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php b/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php index 54e7bde0c..f0974b0c0 100644 --- a/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php +++ b/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php @@ -7,7 +7,10 @@ use Drupal\Core\Url; /** - * Emits a Node for generating derivatives event. + * Emits a Media for generating derivatives event. + * + * Attaches the result as a file in a file field on the emitting + * Media ("multi-file media"). * * @Action( * id = "generate_derivative_file", @@ -88,19 +91,33 @@ protected function generateData(EntityInterface $entity) { */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $form = parent::buildConfigurationForm($form, $form_state); + $map = $this->entityFieldManager->getFieldMapByFieldType('file'); $file_fields = $map['media']; $file_options = array_combine(array_keys($file_fields), array_keys($file_fields)); - $file_options = array_merge(['' => ''], $file_options); + + $map = $this->entityFieldManager->getFieldMapByFieldType('image'); + $image_fields = $map['media']; + $image_options = array_combine(array_keys($image_fields), array_keys($image_fields)); + + $file_options = array_merge(['' => ''], $file_options, $image_options); + + // @todo figure out how to write to thumbnail, which is not a real field. + // see https://github.com/Islandora/islandora/issues/891. + unset($file_options['thumbnail']); + $form['event']['#disabled'] = 'disabled'; $form['destination_field_name'] = [ '#required' => TRUE, '#type' => 'select', '#options' => $file_options, - '#title' => $this->t('Destination File field Name'), + '#title' => $this->t('Destination File field'), '#default_value' => $this->configuration['destination_field_name'], - '#description' => $this->t('File field on Media Type to hold derivative. Cannot be the same as source'), + '#description' => $this->t('This Action stores a derivative file + in a File or Image field on a media. The destination field + must be an additional field, not the media\'s main storage field. + Selected destination field must be present on the media.'), ]; $form['args'] = [ From 48b5333b2d8d84c5bdf3ed494aaa89085cc3c82f Mon Sep 17 00:00:00 2001 From: shriram1056 Date: Fri, 25 Nov 2022 11:36:09 -0400 Subject: [PATCH 17/37] skip entity types protected by entity integrity reference and updated test cases for toggle feature --- config/install/islandora.settings.yml | 1 + config/schema/islandora.schema.yml | 5 +- islandora.module | 50 ++++++++++++------- .../Functional/DeleteNodeWithMediaAndFile.php | 5 ++ 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/config/install/islandora.settings.yml b/config/install/islandora.settings.yml index 8fb25fb8c..179d42132 100644 --- a/config/install/islandora.settings.yml +++ b/config/install/islandora.settings.yml @@ -1,4 +1,5 @@ broker_url: 'tcp://localhost:61613' jwt_expiry: '+2 hour' gemini_url: '' +delete_media_and_files: TRUE gemini_pseudo_bundles: [] diff --git a/config/schema/islandora.schema.yml b/config/schema/islandora.schema.yml index e85d57396..86b65fd0c 100644 --- a/config/schema/islandora.schema.yml +++ b/config/schema/islandora.schema.yml @@ -14,6 +14,9 @@ islandora.settings: jwt_expiry: type: string label: 'How long JWTs should last before expiring.' + delete_media_and_files: + type: boolean + label: 'Node Delete with Media and Files' upload_form_location: type: string label: 'Upload Form Location' @@ -166,7 +169,7 @@ condition.plugin.node_had_namespace: pid_field: type: ignore label: 'PID field' - + field.formatter.settings.islandora_image: type: field.formatter.settings.image label: 'Islandora image field display format settings' diff --git a/islandora.module b/islandora.module index 5cab2ccee..b651f2915 100644 --- a/islandora.module +++ b/islandora.module @@ -373,6 +373,7 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) } } } + return $form; } @@ -390,7 +391,6 @@ function islandora_object_delete_form_submit($form, &$form_state) { $medias = $utils->getMedia($node); $media_list = ""; - $entity_type_manager = \Drupal::entityTypeManager(); $entity_field_manager = \Drupal::service('entity_field.manager'); $current_user = \Drupal::currentUser(); $logger = \Drupal::logger('logger.channel.islandora'); @@ -398,14 +398,12 @@ function islandora_object_delete_form_submit($form, &$form_state) { $total_count = 0; $delete_media = []; - $delete_media_translations = []; - $delete_files = []; + $media_translations = []; + $media_files = []; + $entity_protected_medias = []; $inaccessible_entities = []; - $media_storage = $entity_type_manager->getStorage('media'); - $file_storage = $entity_type_manager->getStorage('file'); foreach ($medias as $id => $media) { - $media_list .= $id . ", "; $lang = $media->language()->getId(); $selected_langcodes[$lang] = $lang; @@ -425,7 +423,7 @@ function islandora_object_delete_form_submit($form, &$form_state) { $inaccessible_entities[] = $file; continue; } - $delete_files[$file->id()] = $file; + $media_files[$id][$file->id()] = $file; $total_count++; } } @@ -436,33 +434,49 @@ function islandora_object_delete_form_submit($form, &$form_state) { $entity = $media->getTranslation($langcode); if ($entity->isDefaultTranslation()) { $delete_media[$id] = $entity; - unset($delete_media_translations[$id]); + unset($media_translations[$id]); $total_count += count($entity->getTranslationLanguages()); } elseif (!isset($delete_media[$id])) { - $delete_media_translations[$id][] = $entity; + $media_translations[$id][] = $entity; } } } if ($delete_media) { - $media_storage->delete($delete_media); foreach ($delete_media as $media) { - $logger->notice('The media %label has been deleted.', [ - '%label' => $media->label(), - ]); + try { + $media->delete(); + $logger->notice('The media %label has been deleted.', [ + '%label' => $media->label(), + ]); + $media_list .= $id . ", "; + } + catch (Exception $e) { + $entity_protected_medias[] = $id; + } } } + $delete_files = array_filter($media_files, function ($media) use ($entity_protected_medias) { + return !in_array($media, $entity_protected_medias); + }, ARRAY_FILTER_USE_KEY); + if ($delete_files) { - $file_storage->delete($delete_files); - foreach ($delete_files as $file) { - $logger->notice('The file %label has been deleted.', [ - '%label' => $file->label(), - ]); + foreach ($delete_files as $files_array) { + foreach ($files_array as $file) { + $file->delete(); + $logger->notice('The file %label has been deleted.', [ + '%label' => $file->label(), + ]); + } } } + $delete_media_translations = array_filter($media_translations, function ($media) use ($entity_protected_medias) { + return !in_array($media, $entity_protected_medias); + }, ARRAY_FILTER_USE_KEY); + if ($delete_media_translations) { foreach ($delete_media_translations as $id => $translations) { $media = $medias[$id]; diff --git a/tests/src/Functional/DeleteNodeWithMediaAndFile.php b/tests/src/Functional/DeleteNodeWithMediaAndFile.php index ff793f0da..40e469c5c 100644 --- a/tests/src/Functional/DeleteNodeWithMediaAndFile.php +++ b/tests/src/Functional/DeleteNodeWithMediaAndFile.php @@ -19,6 +19,7 @@ public function testDeleteNodeWithMediaAndFile() { 'view media', 'bypass node access', 'access files overview', + 'administer site configuration', ]); $this->drupalLogin($account); @@ -75,6 +76,10 @@ public function testDeleteNodeWithMediaAndFile() { ]); $media2->save(); + $this->drupalGet("admin/config/islandora/core"); + $assert_session->pageTextContains('Node Delete with Media and Files'); + \Drupal::configFactory()->getEditable('islandora.settings')->set('delete_media_and_files', TRUE)->save(); + $delete = ['delete_associated_content' => TRUE]; $this->drupalGet("node/1/delete"); From e15b6322ff98df666a0df16200904a33cd8a2de0 Mon Sep 17 00:00:00 2001 From: shriram1056 Date: Fri, 25 Nov 2022 13:28:24 -0400 Subject: [PATCH 18/37] fixed log message --- islandora.module | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/islandora.module b/islandora.module index b651f2915..05e18c4ac 100644 --- a/islandora.module +++ b/islandora.module @@ -444,13 +444,13 @@ function islandora_object_delete_form_submit($form, &$form_state) { } if ($delete_media) { - foreach ($delete_media as $media) { + foreach ($delete_media as $id => $media) { try { $media->delete(); + $media_list .= $id . ", "; $logger->notice('The media %label has been deleted.', [ '%label' => $media->label(), ]); - $media_list .= $id . ", "; } catch (Exception $e) { $entity_protected_medias[] = $id; From 541620493b197052dd42b9584eb1cb6e36b6699c Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 30 Nov 2022 10:07:19 -0400 Subject: [PATCH 19/37] Updates settings and view for filehash^2. --- composer.json | 2 +- .../config/install/filehash.settings.yml | 21 ++- .../install/views.view.file_checksum.yml | 159 ++++++++++-------- 3 files changed, 109 insertions(+), 73 deletions(-) diff --git a/composer.json b/composer.json index c02d7c168..8fe708edb 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "islandora/jsonld": "^2", "stomp-php/stomp-php": "4.* || ^5", "drupal/jwt": "^1.0.0-beta5", - "drupal/filehash": "^1.1 || ^2", + "drupal/filehash": "^2", "drupal/prepopulate" : "^2.2", "drupal/eva" : "^2.0", "drupal/features" : "^3.7", diff --git a/modules/islandora_core_feature/config/install/filehash.settings.yml b/modules/islandora_core_feature/config/install/filehash.settings.yml index 7deecc696..1ac77eec5 100644 --- a/modules/islandora_core_feature/config/install/filehash.settings.yml +++ b/modules/islandora_core_feature/config/install/filehash.settings.yml @@ -1,5 +1,24 @@ algos: - sha1: sha1 + blake2b_128: '0' + blake2b_160: '0' + blake2b_224: '0' + blake2b_256: '0' + blake2b_384: '0' + blake2b_512: '0' md5: '0' + sha1: sha1 + sha224: '0' sha256: '0' + sha384: '0' + sha512_224: '0' + sha512_256: '0' + sha512: '0' + sha3_224: '0' + sha3_256: '0' + sha3_384: '0' + sha3_512: '0' dedupe: 0 +rehash: false +original: false +dedupe_original: false +mime_types: { } diff --git a/modules/islandora_core_feature/config/install/views.view.file_checksum.yml b/modules/islandora_core_feature/config/install/views.view.file_checksum.yml index b498ba666..a9fd45840 100644 --- a/modules/islandora_core_feature/config/install/views.view.file_checksum.yml +++ b/modules/islandora_core_feature/config/install/views.view.file_checksum.yml @@ -1,14 +1,14 @@ langcode: en status: true dependencies: - enforced: - module: - - islandora_core_feature module: - file - filehash - rest - serialization + enforced: + module: + - islandora_core_feature id: file_checksum label: 'File Checksum' module: views @@ -16,71 +16,24 @@ description: 'Exposes a REST endpoint for getting the checksum of a File' tag: '' base_table: file_managed base_field: fid -core: 8.x display: default: - display_plugin: default id: default display_title: Master + display_plugin: default position: 0 display_options: - access: - type: none - options: { } - cache: - type: tag - options: { } - query: - type: views_query - options: - disable_sql_rewrite: false - distinct: false - replica: false - query_comment: '' - query_tags: { } - 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 - pager: - type: mini - options: - items_per_page: 10 - offset: 0 - id: 0 - total_pages: null - 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 - tags: - previous: ‹‹ - next: ›› - style: - type: serializer - row: - type: 'entity:file' - options: - relationship: none - view_mode: default fields: sha1: id: sha1 - table: filehash + table: file_managed field: sha1 relationship: none group_type: group admin_label: '' + entity_type: file + entity_field: sha1 + plugin_id: field label: '' exclude: false alter: @@ -92,7 +45,7 @@ display: external: false replace_spaces: false path_case: none - trim_whitespace: false + trim_whitespace: true alt: '' rel: '' link_class: '' @@ -106,7 +59,7 @@ display: more_link: false more_link_text: '' more_link_path: '' - strip_tags: false + strip_tags: true trim: false preserve_tags: '' html: false @@ -122,13 +75,55 @@ display: hide_empty: false empty_zero: false hide_alter_empty: true - plugin_id: standard - filters: { } - sorts: { } - header: { } - footer: { } + click_sort_column: value + type: filehash + settings: { } + 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 + pager: + type: mini + options: + offset: 0 + 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: { } - relationships: { } + sorts: { } arguments: fid: id: fid @@ -137,6 +132,9 @@ display: relationship: none group_type: group admin_label: '' + entity_type: file + entity_field: fid + plugin_id: file_fid default_action: 'not found' exception: value: all @@ -151,8 +149,8 @@ display: summary_options: base_path: '' count: true - items_per_page: 25 override: false + items_per_page: 25 summary: sort_order: asc number_of_records: 0 @@ -164,31 +162,46 @@ display: validate_options: { } break_phrase: false not: false - entity_type: file - entity_field: fid - plugin_id: file_fid + filters: { } + style: + type: serializer + row: + type: 'entity:file' + options: + relationship: none + view_mode: default + query: + type: views_query + options: + query_comment: '' + disable_sql_rewrite: false + distinct: false + replica: false + query_tags: { } + relationships: { } + header: { } + footer: { } display_extenders: { } cache_metadata: max-age: -1 contexts: + - 'languages:language_content' - 'languages:language_interface' - request_format - url - url.query_args tags: { } rest_export_1: - display_plugin: rest_export id: rest_export_1 display_title: 'REST export' + display_plugin: rest_export position: 1 display_options: - display_extenders: { } - path: checksum/%file pager: type: some options: - items_per_page: 10 offset: 0 + items_per_page: 10 style: type: serializer options: @@ -198,6 +211,8 @@ display: type: data_field options: field_options: { } + display_extenders: { } + path: checksum/%file auth: - basic_auth - jwt_auth @@ -205,7 +220,9 @@ display: cache_metadata: max-age: -1 contexts: + - 'languages:language_content' - 'languages:language_interface' - request_format - url tags: { } + From def4fda5b6021f6d14288a6880762150648a677f Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 30 Nov 2022 10:51:05 -0400 Subject: [PATCH 20/37] Include original hash, and re-hash. --- .../config/install/filehash.settings.yml | 4 +- .../install/views.view.file_checksum.yml | 85 ++++++++++++++++++- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/modules/islandora_core_feature/config/install/filehash.settings.yml b/modules/islandora_core_feature/config/install/filehash.settings.yml index 1ac77eec5..3dcae2973 100644 --- a/modules/islandora_core_feature/config/install/filehash.settings.yml +++ b/modules/islandora_core_feature/config/install/filehash.settings.yml @@ -18,7 +18,7 @@ algos: sha3_384: '0' sha3_512: '0' dedupe: 0 -rehash: false -original: false +rehash: true +original: true dedupe_original: false mime_types: { } diff --git a/modules/islandora_core_feature/config/install/views.view.file_checksum.yml b/modules/islandora_core_feature/config/install/views.view.file_checksum.yml index a9fd45840..2c8191013 100644 --- a/modules/islandora_core_feature/config/install/views.view.file_checksum.yml +++ b/modules/islandora_core_feature/config/install/views.view.file_checksum.yml @@ -6,6 +6,7 @@ dependencies: - filehash - rest - serialization + - user enforced: module: - islandora_core_feature @@ -88,6 +89,70 @@ display: multi_type: separator separator: ', ' field_api_classes: false + original_sha1: + id: original_sha1 + table: file_managed + field: original_sha1 + relationship: none + group_type: group + admin_label: '' + entity_type: file + entity_field: original_sha1 + 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: true + 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: true + 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: false + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: filehash + settings: { } + 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 pager: type: mini options: @@ -117,8 +182,9 @@ display: sort_asc_label: Asc sort_desc_label: Desc access: - type: none - options: { } + type: perm + options: + perm: 'view checksums' cache: type: tag options: { } @@ -190,6 +256,7 @@ display: - request_format - url - url.query_args + - user.permissions tags: { } rest_export_1: id: rest_export_1 @@ -211,7 +278,18 @@ display: type: data_field options: field_options: { } - display_extenders: { } + display_extenders: + matomo: + enabled: false + keyword_gets: '' + keyword_behavior: first + keyword_concat_separator: ' ' + category_behavior: none + category_gets: '' + category_concat_separator: ' ' + category_fallback: '' + category_facets: { } + category_facets_concat_separator: ', ' path: checksum/%file auth: - basic_auth @@ -224,5 +302,6 @@ display: - 'languages:language_interface' - request_format - url + - user.permissions tags: { } From 5f4a6ab3ae474f8c4e11bddb85feb36e386a2b54 Mon Sep 17 00:00:00 2001 From: Jason Hildebrand Date: Thu, 1 Dec 2022 14:24:35 -0600 Subject: [PATCH 21/37] Eliminate warnings when using NodeHasMediaUse views filter. (#914) --- src/Plugin/views/filter/NodeHasMediaUse.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Plugin/views/filter/NodeHasMediaUse.php b/src/Plugin/views/filter/NodeHasMediaUse.php index 0209505d6..3c69bddd5 100644 --- a/src/Plugin/views/filter/NodeHasMediaUse.php +++ b/src/Plugin/views/filter/NodeHasMediaUse.php @@ -18,10 +18,10 @@ class NodeHasMediaUse extends FilterPluginBase { * {@inheritdoc} */ protected function defineOptions() { - return [ - 'use_uri' => ['default' => NULL], - 'negated' => ['default' => FALSE], - ]; + $options = parent::defineOptions(); + $options['use_uri'] = ['default' => NULL]; + $options['negated'] = ['default' => FALSE]; + return $options; } /** From f71f6dc2e874e85855038a107fdc163cff183038 Mon Sep 17 00:00:00 2001 From: Jason Hildebrand Date: Thu, 1 Dec 2022 16:13:40 -0600 Subject: [PATCH 22/37] Fix warning by checking whether key is set. (#909) * Fix warning by checking whether key is set. * Adjust plugin check in integer-weight views hook. --- islandora.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/islandora.module b/islandora.module index 5b5446d13..9814820e2 100644 --- a/islandora.module +++ b/islandora.module @@ -515,7 +515,7 @@ function islandora_preprocess_views_view_table(&$variables) { // Check for a weight selector field. foreach ($variables['view']->field as $field_key => $field) { - if ($field->options['plugin_id'] == 'integer_weight_selector') { + if ($field->getPluginId() == 'integer_weight_selector') { // Check if the weight selector is on the first column. $is_first_column = array_search($field_key, array_keys($variables['view']->field)) > 0 ? FALSE : TRUE; From 6c582a870227ac39022b2a20df4a554a1e2c54e3 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Thu, 1 Dec 2022 19:05:49 -0400 Subject: [PATCH 23/37] Permit newer version of migrate_plus. This version has PHP 8.1 support. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index eebdd9ab7..29b408948 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "drupal/prepopulate" : "^2.2", "drupal/eva" : "^3.0", "drupal/features" : "^3.7", - "drupal/migrate_plus" : "^5.1", + "drupal/migrate_plus" : "^5.1 || ^6", "drupal/migrate_source_csv" : "^3.4", "drupal/token" : "^1.3", "drupal/flysystem" : "^2.0@alpha", From ee85472dc8b0d2e0517f7cc787da7f73271cf63b Mon Sep 17 00:00:00 2001 From: shriram1056 Date: Fri, 2 Dec 2022 16:36:04 -0400 Subject: [PATCH 24/37] minor changes and post_update for delete_media_and_files --- css/{islandora.theme.css => islandora.css} | 0 islandora.libraries.yml | 4 +-- islandora.module | 32 +++++++++++++--------- islandora.post_update.php | 16 +++++++++++ src/Form/IslandoraSettingsForm.php | 2 +- 5 files changed, 38 insertions(+), 16 deletions(-) rename css/{islandora.theme.css => islandora.css} (100%) create mode 100644 islandora.post_update.php diff --git a/css/islandora.theme.css b/css/islandora.css similarity index 100% rename from css/islandora.theme.css rename to css/islandora.css diff --git a/islandora.libraries.yml b/islandora.libraries.yml index 047006bfe..840dc294b 100644 --- a/islandora.libraries.yml +++ b/islandora.libraries.yml @@ -1,5 +1,5 @@ -drupal.islandora.theme_css: +islandora: version: VERSION css: theme: - css/islandora.theme.css: {} + css/islandora.css: {} diff --git a/islandora.module b/islandora.module index 05e18c4ac..64b65ca84 100644 --- a/islandora.module +++ b/islandora.module @@ -355,7 +355,16 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) $media_list[] = $media->getName(); } - $form['media_items'] = [ + $form['container'] = [ + '#type' => 'container', + '#states' => [ + 'visible' => [ + ':input[name="delete_associated_content"]' => ['checked' => TRUE], + ], + ], + ]; + + $form['container']['media_items'] = [ '#theme' => 'item_list', '#type' => 'ul', '#items' => $media_list, @@ -363,7 +372,7 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) '#wrapper_attributes' => ['class' => ['container']], '#attached' => [ 'library' => [ - 'islandora/drupal.islandora.theme_css', + 'islandora/islandora', ], ], ]; @@ -380,7 +389,7 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id) /** * Implements a submit handler for the delete form. */ -function islandora_object_delete_form_submit($form, &$form_state) { +function islandora_object_delete_form_submit($form, FormStateInterface $form_state) { $result = $form_state->getValues('delete_associated_content'); $utils = \Drupal::service('islandora.utils'); @@ -389,14 +398,13 @@ function islandora_object_delete_form_submit($form, &$form_state) { $node = $form_state->getFormObject()->getEntity(); $medias = $utils->getMedia($node); - $media_list = ""; + $media_list = []; $entity_field_manager = \Drupal::service('entity_field.manager'); $current_user = \Drupal::currentUser(); $logger = \Drupal::logger('logger.channel.islandora'); $messenger = \Drupal::messenger(); - $total_count = 0; $delete_media = []; $media_translations = []; $media_files = []; @@ -424,7 +432,6 @@ function islandora_object_delete_form_submit($form, &$form_state) { continue; } $media_files[$id][$file->id()] = $file; - $total_count++; } } } @@ -435,7 +442,6 @@ function islandora_object_delete_form_submit($form, &$form_state) { if ($entity->isDefaultTranslation()) { $delete_media[$id] = $entity; unset($media_translations[$id]); - $total_count += count($entity->getTranslationLanguages()); } elseif (!isset($delete_media[$id])) { $media_translations[$id][] = $entity; @@ -447,7 +453,7 @@ function islandora_object_delete_form_submit($form, &$form_state) { foreach ($delete_media as $id => $media) { try { $media->delete(); - $media_list .= $id . ", "; + $media_list[] = $id; $logger->notice('The media %label has been deleted.', [ '%label' => $media->label(), ]); @@ -490,12 +496,11 @@ function islandora_object_delete_form_submit($form, &$form_state) { '@language' => $translation->language()->getName(), ]); } - $total_count += count($translations); } } if ($inaccessible_entities) { - $messenger->addWarning("@count items has not been deleted because you do not have the necessary permissions.", [ + $messenger->addWarning("@count items have not been deleted because you do not have the necessary permissions.", [ '@count' => count($inaccessible_entities), ]); } @@ -507,9 +512,10 @@ function islandora_object_delete_form_submit($form, &$form_state) { '#value' => t("The repository item @node and @media", [ '@node' => $node->getTitle(), '@media' => \Drupal::translation()->formatPlural( - substr_count($media_list, ",") + 1, 'the media with the id @media has been deleted.', - 'the medias with the id @media have been deleted.', - ['@media' => mb_substr($media_list, 0, strlen($media_list) - 2)]), + count($media_list), 'the media with the id @media has been deleted.', + 'the medias with the ids @media have been deleted.', + ['@media' => implode(", ", $media_list)], + ), ]), ], ]; diff --git a/islandora.post_update.php b/islandora.post_update.php new file mode 100644 index 000000000..0a29e56ed --- /dev/null +++ b/islandora.post_update.php @@ -0,0 +1,16 @@ +getEditable('islandora.settings'); + $config->set('delete_media_and_files', TRUE); + $config->save(TRUE); +} diff --git a/src/Form/IslandoraSettingsForm.php b/src/Form/IslandoraSettingsForm.php index a65ab82f0..90e0b4204 100644 --- a/src/Form/IslandoraSettingsForm.php +++ b/src/Form/IslandoraSettingsForm.php @@ -205,7 +205,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { $form[self::NODE_DELETE_MEDIA_AND_FILES] = [ '#type' => 'checkbox', '#title' => $this->t('Node Delete with Media and Files'), - '#description' => $this->t('adds a checkbox in the "Delete" tab of islandora objects to delete media and files associated with the object.' + '#description' => $this->t('Adds a checkbox in the "Delete" tab of islandora objects to delete media and files associated with the object.' ), '#default_value' => (bool) $config->get(self::NODE_DELETE_MEDIA_AND_FILES), ]; From b47d37b1b69c97540a7ea7a772d7785040fbace7 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Tue, 6 Dec 2022 19:48:55 -0400 Subject: [PATCH 25/37] Fix errors when OCR field not set. --- .../islandora_iiif/src/Plugin/views/style/IIIFManifest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php b/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php index cc4b5e94e..c2a2fbc3c 100644 --- a/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php +++ b/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php @@ -205,11 +205,13 @@ protected function getTileSourceFromRow(ResultRow $row, $iiif_address, $iiif_bas continue; } - $ocrs = $entity->{$ocrField->definition['field_name']}; + if (!is_null($ocrField)) { + $ocrs = $entity->{$ocrField->definition['field_name']}; + $ocr = isset($ocrs[$i]) ? $ocrs[$i] : FALSE; + } // Create the IIIF URL for this file // Visiting $iiif_url will resolve to the info.json for the image. - $ocr = isset($ocrs[$i]) ? $ocrs[$i] : FALSE; $file_url = $image->entity->createFileUrl(FALSE); $mime_type = $image->entity->getMimeType(); $iiif_url = rtrim($iiif_address, '/') . '/' . urlencode($file_url); From 0b7f12d3baeefc230fcc6f426e668a3d5ab27247 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Fri, 9 Dec 2022 11:41:36 -0400 Subject: [PATCH 26/37] No infinite derivatives. --- src/EventGenerator/EmitEvent.php | 4 ++++ src/Plugin/Action/AbstractGenerateDerivative.php | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/EventGenerator/EmitEvent.php b/src/EventGenerator/EmitEvent.php index 683f3e8b6..2e0d226e4 100644 --- a/src/EventGenerator/EmitEvent.php +++ b/src/EventGenerator/EmitEvent.php @@ -157,6 +157,10 @@ public function execute($entity = NULL) { $user = $this->entityTypeManager->getStorage('user')->load($this->account->id()); $data = $this->generateData($entity); + // If $data is the bool false, then abort. No error, but don't emit event. + if ($data === FALSE) { + return; + } $event = $this->eventDispatcher->dispatch( StompHeaderEvent::EVENT_NAME, diff --git a/src/Plugin/Action/AbstractGenerateDerivative.php b/src/Plugin/Action/AbstractGenerateDerivative.php index b22201e11..129af9944 100644 --- a/src/Plugin/Action/AbstractGenerateDerivative.php +++ b/src/Plugin/Action/AbstractGenerateDerivative.php @@ -60,6 +60,13 @@ protected function generateData(EntityInterface $entity) { throw new \RuntimeException("Could not locate taxonomy term with uri: " . $this->configuration['derivative_term_uri'], 500); } + // See if there is a destination media already set, and abort if it's the + // same as the source media. Dont cause an error, just don't continue. + $derivative_media = $this->utils->getMediaWithTerm($entity, $derivative_term); + if (!is_null($derivative_media) && $derivative_media->id() == $source_media->id()) { + return FALSE; + } + $route_params = [ 'node' => $entity->id(), 'media_type' => $this->configuration['destination_media_type'], From f86f2bedb17e40b8989ddbb4f388fede0bf68ba7 Mon Sep 17 00:00:00 2001 From: dannylamb Date: Mon, 12 Dec 2022 10:22:30 -0400 Subject: [PATCH 27/37] Updating default config for GenerateOCRDerivative.php --- .../src/Plugin/Action/GenerateOCRDerivative.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php b/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php index 745c57727..63a714a80 100644 --- a/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php +++ b/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php @@ -22,9 +22,13 @@ class GenerateOCRDerivative extends AbstractGenerateDerivative { public function defaultConfiguration() { $config = parent::defaultConfiguration(); $config['path'] = '[date:custom:Y]-[date:custom:m]/[node:nid]-[term:name].txt'; - $config['mimetype'] = 'application/xml'; + $config['event'] = 'Generate Derivative'; + $config['source_term_uri'] = 'http://pcdm.org/use#OriginalFile'; + $config['derivative_term_uri'] = 'http://pcdm.org/use#ExtractedText'; + $config['mimetype'] = 'text/plain'; $config['queue'] = 'islandora-connector-ocr'; - $config['destination_media_type'] = 'file'; + $config['destination_media_type'] = 'extracted_text'; + $config['scheme'] = 'fedora'; return $config; } From 41f87101226ec466ba369dcd3b98b42255dd48da Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Tue, 13 Dec 2022 16:43:06 -0400 Subject: [PATCH 28/37] Use a proper exception. --- src/EventGenerator/EmitEvent.php | 9 +++++---- src/Exception/IslandoraDerivativeException.php | 12 ++++++++++++ src/Plugin/Action/AbstractGenerateDerivative.php | 3 ++- 3 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 src/Exception/IslandoraDerivativeException.php diff --git a/src/EventGenerator/EmitEvent.php b/src/EventGenerator/EmitEvent.php index 2e0d226e4..fd33fd99c 100644 --- a/src/EventGenerator/EmitEvent.php +++ b/src/EventGenerator/EmitEvent.php @@ -14,6 +14,7 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\islandora\Event\StompHeaderEvent; use Drupal\islandora\Event\StompHeaderEventException; +use Drupal\islandora\Exception\IslandoraDerivativeException; use Stomp\Exception\StompException; use Stomp\StatefulStomp; use Stomp\Transport\Message; @@ -157,10 +158,6 @@ public function execute($entity = NULL) { $user = $this->entityTypeManager->getStorage('user')->load($this->account->id()); $data = $this->generateData($entity); - // If $data is the bool false, then abort. No error, but don't emit event. - if ($data === FALSE) { - return; - } $event = $this->eventDispatcher->dispatch( StompHeaderEvent::EVENT_NAME, @@ -172,6 +169,10 @@ public function execute($entity = NULL) { $event->getHeaders()->all() ); } + catch (IslandoraDerivativeException $e) { + $this->logger->info($e->getMessage()); + return; + } catch (StompHeaderEventException $e) { $this->logger->error($e->getMessage()); $this->messenger->addError($e->getMessage()); diff --git a/src/Exception/IslandoraDerivativeException.php b/src/Exception/IslandoraDerivativeException.php new file mode 100644 index 000000000..66f636065 --- /dev/null +++ b/src/Exception/IslandoraDerivativeException.php @@ -0,0 +1,12 @@ +utils->getMediaWithTerm($entity, $derivative_term); if (!is_null($derivative_media) && $derivative_media->id() == $source_media->id()) { - return FALSE; + throw new IslandoraDerivativeException("Halting derivative, as source and target media are the same. Derivative term: [" . $this->configuration['derivative_term_uri'] . "] Source term: [" . $this->configuration['source_term_uri'] . "] Node id: [". $entity->id() . "].", 500); } $route_params = [ From 665abfbd6c48418c30eb30a57fb394fe07a2b715 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Tue, 13 Dec 2022 17:12:44 -0400 Subject: [PATCH 29/37] phpcs. --- src/Exception/IslandoraDerivativeException.php | 3 +-- src/Plugin/Action/AbstractGenerateDerivative.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Exception/IslandoraDerivativeException.php b/src/Exception/IslandoraDerivativeException.php index 66f636065..7efe47736 100644 --- a/src/Exception/IslandoraDerivativeException.php +++ b/src/Exception/IslandoraDerivativeException.php @@ -7,6 +7,5 @@ * * @package islandora */ -class IslandoraDerivativeException extends \RuntimeException -{ +class IslandoraDerivativeException extends \RuntimeException { } diff --git a/src/Plugin/Action/AbstractGenerateDerivative.php b/src/Plugin/Action/AbstractGenerateDerivative.php index 339d1d877..b44db477b 100644 --- a/src/Plugin/Action/AbstractGenerateDerivative.php +++ b/src/Plugin/Action/AbstractGenerateDerivative.php @@ -65,7 +65,7 @@ protected function generateData(EntityInterface $entity) { // same as the source media. Dont cause an error, just don't continue. $derivative_media = $this->utils->getMediaWithTerm($entity, $derivative_term); if (!is_null($derivative_media) && $derivative_media->id() == $source_media->id()) { - throw new IslandoraDerivativeException("Halting derivative, as source and target media are the same. Derivative term: [" . $this->configuration['derivative_term_uri'] . "] Source term: [" . $this->configuration['source_term_uri'] . "] Node id: [". $entity->id() . "].", 500); + throw new IslandoraDerivativeException("Halting derivative, as source and target media are the same. Derivative term: [" . $this->configuration['derivative_term_uri'] . "] Source term: [" . $this->configuration['source_term_uri'] . "] Node id: [" . $entity->id() . "].", 500); } $route_params = [ From 7df45a083a21e33c17026ff9629d32abe5a91463 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Tue, 13 Dec 2022 19:22:12 -0400 Subject: [PATCH 30/37] Use new syntax for filehash. --- islandora.module | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/islandora.module b/islandora.module index 5b5446d13..faf24fdc9 100644 --- a/islandora.module +++ b/islandora.module @@ -181,7 +181,8 @@ function islandora_file_insert(FileInterface $file) { */ function islandora_file_update(FileInterface $file) { // Exit early if unchanged. - if ($file->filehash != NULL && $file->original->filehash != NULL && $file->filehash['sha1'] == $file->original->filehash['sha1']) { + if ($file->hasField('sha1') && $file->original->hasField('sha1') + && $file->sha1->getString() == $file->original->sha1->getString()) { return; } From b326d967a692ac0051ce4fed0c3c99bb8243a964 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 14 Dec 2022 10:39:01 -0400 Subject: [PATCH 31/37] Update dependencies. --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 43533a690..c1bfaa2d9 100644 --- a/composer.json +++ b/composer.json @@ -14,11 +14,11 @@ } ], "require": { - "drupal/context": "^4.0@beta", - "drupal/search_api": "~1.8", + "drupal/context": "^4", + "drupal/search_api": "^1.8", "islandora/jsonld": "^2", "stomp-php/stomp-php": "4.* || ^5", - "drupal/jwt": "^1.0.0-beta5", + "drupal/jwt": "^1.0", "drupal/filehash": "^2", "drupal/prepopulate" : "^2.2", "drupal/eva" : "^3.0", From 12e28f1284ef32052414a0e0a3cd74158813259e Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 14 Dec 2022 10:39:37 -0400 Subject: [PATCH 32/37] Sort dependencies. --- composer.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index c1bfaa2d9..0b443c027 100644 --- a/composer.json +++ b/composer.json @@ -15,21 +15,21 @@ ], "require": { "drupal/context": "^4", - "drupal/search_api": "^1.8", - "islandora/jsonld": "^2", - "stomp-php/stomp-php": "4.* || ^5", - "drupal/jwt": "^1.0", - "drupal/filehash": "^2", - "drupal/prepopulate" : "^2.2", + "drupal/ctools": "^3.8 || ^4", "drupal/eva" : "^3.0", "drupal/features" : "^3.7", + "drupal/file_replace": "^1.1", + "drupal/filehash": "^2", + "drupal/flysystem" : "^2.0@alpha", + "drupal/jwt": "^1.0", "drupal/migrate_plus" : "^5.1 || ^6", "drupal/migrate_source_csv" : "^3.4", + "drupal/prepopulate" : "^2.2", + "drupal/search_api": "^1.8", "drupal/token" : "^1.3", - "drupal/flysystem" : "^2.0@alpha", "islandora/crayfish-commons": "^2", - "drupal/file_replace": "^1.1", - "drupal/ctools": "^3.8 || ^4" + "islandora/jsonld": "^2", + "stomp-php/stomp-php": "4.* || ^5" }, "require-dev": { "phpunit/phpunit": "^6", From cefee615c0477a1067fc703074da7aa6b24a57bd Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 14 Dec 2022 13:54:33 -0400 Subject: [PATCH 33/37] Warn re. tiffs and jp2s in image file derivatives. (#921) * Warn re. tiffs and jp2s in image file derivatives. * Update wording. --- .../src/Plugin/Action/GenerateImageDerivativeFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php index e0420fe8f..a6e067740 100644 --- a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php +++ b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php @@ -51,7 +51,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#title' => $this->t('Destination Image field'), '#default_value' => $this->configuration['destination_field_name'], '#description' => $this->t('This Action stores the derivative in an - Image field. If you need to store the result in a File field, use + Image field. If you are creating a TIFF or JP2, instead use "Generate a Derivative File for Media Attachment". Selected target field must be an additional field, not the media\'s main storage field. Selected target field must be present on the media.'), From 6f2955b0613a6b6073801cf677fccd52a8182d80 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 6 Jan 2023 16:01:03 -0400 Subject: [PATCH 34/37] Avoid ::referencedEntities() call when it is not expected to exist. (#923) --- src/MediaSource/MediaSourceService.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/MediaSource/MediaSourceService.php b/src/MediaSource/MediaSourceService.php index 60e41672c..533789857 100644 --- a/src/MediaSource/MediaSourceService.php +++ b/src/MediaSource/MediaSourceService.php @@ -3,6 +3,7 @@ namespace Drupal\islandora\MediaSource; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Session\AccountInterface; @@ -113,8 +114,12 @@ public function getSourceFieldName($media_type) { * @param \Drupal\media\MediaInterface $media * Media whose source field you are searching for. * - * @return \Drupal\file\FileInterface - * File if it exists + * @return \Drupal\file\FileInterface|\Drupal\Core\Entity\EntityInterface|false|null + * The first source entity if there is one, generally expected to be of + * \Drupal\file\FileInterface. Boolean FALSE if there was no such entity. + * NULL if the source field does not refer to Drupal entities (as in, the + * field is not a \Drupal\Core\Field\EntityReferenceFieldItemListInterface + * implementation). * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ @@ -127,10 +132,13 @@ public function getSourceFile(MediaInterface $media) { } // Get the file from the media. - $files = $media->get($source_field)->referencedEntities(); - $file = reset($files); + $source_list = $media->get($source_field); + if ($source_list instanceof EntityReferenceFieldItemListInterface) { + $files = $source_list->referencedEntities(); + return reset($files); + } - return $file; + return NULL; } /** From fe7e450a51ef7b3da0afca615e1ecb13f6cf1cc1 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 25 Jan 2023 14:06:51 -0400 Subject: [PATCH 35/37] Index `field_weight`'s value. (#924) --- .../field.storage.node.field_weight.yml | 4 +++- .../islandora_core_feature.post_update.php | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 modules/islandora_core_feature/islandora_core_feature.post_update.php diff --git a/modules/islandora_core_feature/config/install/field.storage.node.field_weight.yml b/modules/islandora_core_feature/config/install/field.storage.node.field_weight.yml index 97619cd26..4976d1d60 100644 --- a/modules/islandora_core_feature/config/install/field.storage.node.field_weight.yml +++ b/modules/islandora_core_feature/config/install/field.storage.node.field_weight.yml @@ -14,6 +14,8 @@ module: core locked: false cardinality: 1 translatable: true -indexes: { } +indexes: + value: + - value persist_with_no_fields: false custom_storage: false diff --git a/modules/islandora_core_feature/islandora_core_feature.post_update.php b/modules/islandora_core_feature/islandora_core_feature.post_update.php new file mode 100644 index 000000000..10547231a --- /dev/null +++ b/modules/islandora_core_feature/islandora_core_feature.post_update.php @@ -0,0 +1,20 @@ +getStorage('field_storage_config'); + $field = $storage->load('node.field_weight'); + $indexes = $field->getIndexes(); + $indexes += [ + 'value' => ['value'], + ]; + $field->setIndexes($indexes); + $field->save(); +} From c36f7d9978fec175a8bec378b922ab822228d1b9 Mon Sep 17 00:00:00 2001 From: JojoVes Date: Wed, 1 Feb 2023 14:23:10 -0400 Subject: [PATCH 36/37] Replace deprecated 'context' condition annotation with 'context_definitions' (#925) There was a cleanup done for this deprecation in https://github.com/Islandora/islandora/pull/764 before the 'NodeReferencedByNode' condition was made, then the deprecated annotation must have just been missed in reviewing https://github.com/Islandora/islandora/pull/808. --- src/Plugin/Condition/NodeReferencedByNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin/Condition/NodeReferencedByNode.php b/src/Plugin/Condition/NodeReferencedByNode.php index a2abac808..c5611a3ee 100644 --- a/src/Plugin/Condition/NodeReferencedByNode.php +++ b/src/Plugin/Condition/NodeReferencedByNode.php @@ -16,7 +16,7 @@ * @Condition( * id = "node_referenced_by_node", * label = @Translation("Node is referenced by other nodes"), - * context = { + * context_definitions = { * "node" = @ContextDefinition("entity:node", required = TRUE , label = @Translation("node")) * } * ) From 2794f01164199525c734ed70d56ae378a2f185a9 Mon Sep 17 00:00:00 2001 From: Ant Brown Date: Thu, 9 Feb 2023 09:30:05 +1300 Subject: [PATCH 37/37] Fix deprecated File::url(), use createFileUrl() instead (#855) * islandora.tokens.inc * See https://www.drupal.org/node/3019830 Co-authored-by: Ant Brown --- islandora.tokens.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/islandora.tokens.inc b/islandora.tokens.inc index 8d1c4b6b2..abbe6474a 100644 --- a/islandora.tokens.inc +++ b/islandora.tokens.inc @@ -79,7 +79,7 @@ function islandora_tokens($type, $tokens, array $data, array $options, Bubbleabl if ($media) { $file = \Drupal::service('islandora.media_source_service')->getSourceFile($media); if (!empty($file)) { - $url = $file->url(); + $url = $file->createFileUrl(); $replacements[$original] = $url; } }