From aa3c71893e7aea98dff67e660df5f3b7832fafb0 Mon Sep 17 00:00:00 2001
From: shriram <saravananshriram80@gmail.com>
Date: Tue, 18 Oct 2022 16:10:19 -0300
Subject: [PATCH 01/32] 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 5b5446d1..708f8ec1 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 <saravananshriram80@gmail.com>
Date: Thu, 27 Oct 2022 14:31:18 -0300
Subject: [PATCH 02/32] 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 708f8ec1..ab9eab18 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.= "<li>{$media->getName()}</li>";
+      }
+
+      $form['media_items'] = array(
+        '#suffix' => "<ul>{$media_list}</ul>", // 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 <saravananshriram80@gmail.com>
Date: Tue, 1 Nov 2022 12:16:29 -0300
Subject: [PATCH 03/32] fixed failing coding standard checks

---
 islandora.module | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/islandora.module b/islandora.module
index ab9eab18..63018266 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.= "<li>{$media->getName()}</li>";
+      foreach ($medias as $media) {
+        $media_list .= "<li>{$media->getName()}</li>";
       }
 
-      $form['media_items'] = array(
-        '#suffix' => "<ul>{$media_list}</ul>", // Add markup after form item
-      );
+      $form['media_items'] = [
+        '#suffix' => "<ul>{$media_list}</ul>",
+      ];
 
       $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 <saravananshriram80@gmail.com>
Date: Tue, 1 Nov 2022 13:08:36 -0300
Subject: [PATCH 04/32] 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 63018266..e8aeb232 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 <saravananshriram80@gmail.com>
Date: Tue, 1 Nov 2022 16:00:22 -0300
Subject: [PATCH 05/32] 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 00000000..b9cc8f99
--- /dev/null
+++ b/tests/src/Functional/DeleteNodeWithMedia.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\Tests\islandora\Functional;
+
+/**
+ * Tests the Delete Node with Media.
+ *
+ * @group islandora
+ */
+class DeleteNodeWithMedia extends IslandoraFunctionalTestBase {
+
+  /**
+   * Tests delete Node and its assoicated media.
+   */
+  public function testDeleteNodeWithMedia() {
+    $account = $this->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 <lefaive@gmail.com>
Date: Sat, 23 Jul 2022 14:43:48 -0300
Subject: [PATCH 06/32] 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 bd670561..a58d9860 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 @@ class ManageMediaController extends ManageMembersController {
       $field,
       ['query' => ["edit[$field][widget][0][target_id]" => $node->id()]]
     );
+
+    return [
+      '#type' => 'markup',
+      '#markup' => $this->t("These available media types below have <em>@field</em> 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 7f480fb3..e07ec5df 100644
--- a/src/Controller/ManageMembersController.php
+++ b/src/Controller/ManageMembersController.php
@@ -88,7 +88,8 @@ class ManageMembersController extends EntityController {
    */
   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 @@ class ManageMembersController extends EntityController {
       $field,
       ['query' => ["edit[$field][widget][0][target_id]" => $node->id()]]
     );
+
+    return [
+      '#type' => 'markup',
+      '#markup' => $this->t("These available content types below have <em>@field</em> 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 <lefaive@gmail.com>
Date: Mon, 7 Nov 2022 17:10:30 -0400
Subject: [PATCH 07/32] 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 a58d9860..d15175f9 100644
--- a/src/Controller/ManageMediaController.php
+++ b/src/Controller/ManageMediaController.php
@@ -36,8 +36,11 @@ class ManageMediaController extends ManageMembersController {
 
     return [
       '#type' => 'markup',
-      '#markup' => $this->t("These available media types below have <em>@field</em> 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 <code>@field</code> field. <a href=@manage_media_page>Manage media types</a>.",
+        [
+          '@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 e07ec5df..bfd2cf74 100644
--- a/src/Controller/ManageMembersController.php
+++ b/src/Controller/ManageMembersController.php
@@ -100,8 +100,11 @@ class ManageMembersController extends EntityController {
 
     return [
       '#type' => 'markup',
-      '#markup' => $this->t("These available content types below have <em>@field</em> 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 <code>@field</code> field. <a href=@manage_content_types>Manage content types</a>.",
+        [
+          '@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 <lefaive@gmail.com>
Date: Mon, 7 Nov 2022 18:36:10 -0400
Subject: [PATCH 08/32] 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 d15175f9..025d1d9d 100644
--- a/src/Controller/ManageMediaController.php
+++ b/src/Controller/ManageMediaController.php
@@ -6,6 +6,7 @@ use Drupal\islandora\IslandoraUtils;
 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 @@ class ManageMediaController extends ManageMembersController {
       ['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 <code>@field</code> field. <a href=@manage_media_page>Manage media types</a>.",
-        [
-          '@field' => $field,
-          '@manage_media_page' => '/admin/structure/media',
-        ]),
+      '#markup' => $this->t("The following media types can be added because they have the <code>@field</code> 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 bfd2cf74..9827ff35 100644
--- a/src/Controller/ManageMembersController.php
+++ b/src/Controller/ManageMembersController.php
@@ -7,6 +7,7 @@ use Drupal\Core\Render\RendererInterface;
 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 @@ class ManageMembersController extends EntityController {
       ['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 <code>@field</code> field. <a href=@manage_content_types>Manage content types</a>.",
-        [
-          '@field' => $field,
-          '@manage_content_types' => '/admin/structure/types',
-        ]),
+      '#markup' => $this->t("The following content types can be added because they have the <code>@field</code> field.", [
+        '@field' => $field,
+      ]),
+      'manage_link' => $manage_link,
       'add_node' => $add_node_list,
     ];
   }

From 7ef1afffa2c814b83decb86e13677ecde764d68f Mon Sep 17 00:00:00 2001
From: shriram <saravananshriram80@gmail.com>
Date: Tue, 8 Nov 2022 13:44:38 -0400
Subject: [PATCH 09/32] 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 e8aeb232..9130caeb 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 .= "<li>{$media->getName()}</li>";
+        $form['actions']['submit']['#submit'][] = 'islandora_object_delete_form_submit';
+        return $form;
       }
-
-      $form['media_items'] = [
-        '#suffix' => "<ul>{$media_list}</ul>",
-      ];
-
-      $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 <saravananshriram80@gmail.com>
Date: Tue, 8 Nov 2022 16:07:27 -0400
Subject: [PATCH 10/32] 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 9130caeb..44dc35a7 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 b9cc8f99..ff793f0d 100644
--- a/tests/src/Functional/DeleteNodeWithMedia.php
+++ b/tests/src/Functional/DeleteNodeWithMediaAndFile.php
@@ -7,17 +7,18 @@ namespace Drupal\Tests\islandora\Functional;
  *
  * @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 @@ class DeleteNodeWithMedia extends IslandoraFunctionalTestBase {
     $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 <saravananshriram80@gmail.com>
Date: Thu, 10 Nov 2022 14:56:58 -0400
Subject: [PATCH 11/32] 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 00000000..696587ac
--- /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 00000000..047006bf
--- /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 44dc35a7..66c74ad5 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 <saravananshriram80@gmail.com>
Date: Tue, 15 Nov 2022 14:35:01 -0400
Subject: [PATCH 12/32] 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 66c74ad5..5cab2cce 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 5049ef16..a65ab82f 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 @@ class IslandoraSettingsForm extends ConfigFormBase {
       $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 @@ class IslandoraSettingsForm extends ConfigFormBase {
       ->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 <lefaive@gmail.com>
Date: Mon, 21 Nov 2022 12:20:20 -0400
Subject: [PATCH 13/32] 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 c02d7c16..eebdd9ab 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 <lefaive@gmail.com>
Date: Mon, 25 Jul 2022 13:43:30 -0300
Subject: [PATCH 14/32] 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 be9eca80..54e7bde0 100644
--- a/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php
+++ b/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php
@@ -88,16 +88,10 @@ class AbstractGenerateDerivativeMediaFile extends AbstractGenerateDerivativeBase
    */
   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 <lefaive@gmail.com>
Date: Tue, 26 Jul 2022 13:31:22 -0300
Subject: [PATCH 15/32] Add Image fields only to Image derivative code.

Co-authored-by: @ajstanley <alanjarlathstanley@gmail.com>
---
 .../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 d6f99b58..54b215f3 100644
--- a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php
+++ b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php
@@ -34,7 +34,23 @@ class GenerateImageDerivativeFile extends AbstractGenerateDerivativeMediaFile {
    */
   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 <lefaive@gmail.com>
Date: Thu, 24 Nov 2022 19:50:10 -0400
Subject: [PATCH 16/32] 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 54b215f3..e0420fe8 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\Core\Form\FormStateInterface;
 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 @@ class GenerateImageDerivativeFile extends AbstractGenerateDerivativeMediaFile {
     $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 @@ class GenerateImageDerivativeFile extends AbstractGenerateDerivativeMediaFile {
       '#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 bab43fcf..3d0e7909 100644
--- a/src/Controller/MediaSourceController.php
+++ b/src/Controller/MediaSourceController.php
@@ -280,8 +280,7 @@ class MediaSourceController extends ControllerBase {
    */
   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 9399e334..60e41672 100644
--- a/src/MediaSource/MediaSourceService.php
+++ b/src/MediaSource/MediaSourceService.php
@@ -268,8 +268,8 @@ class MediaSourceService {
         '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 @@ class MediaSourceService {
         '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 54e7bde0..f0974b0c 100644
--- a/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php
+++ b/src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php
@@ -7,7 +7,10 @@ use Drupal\Core\Form\FormStateInterface;
 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 @@ class AbstractGenerateDerivativeMediaFile extends AbstractGenerateDerivativeBase
    */
   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 <shriram1056@outlook.com>
Date: Fri, 25 Nov 2022 11:36:09 -0400
Subject: [PATCH 17/32] 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 8fb25fb8..179d4213 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 e85d5739..86b65fd0 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 5cab2cce..b651f291 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 ff793f0d..40e469c5 100644
--- a/tests/src/Functional/DeleteNodeWithMediaAndFile.php
+++ b/tests/src/Functional/DeleteNodeWithMediaAndFile.php
@@ -19,6 +19,7 @@ class DeleteNodeWithMediaAndFile extends IslandoraFunctionalTestBase {
       'view media',
       'bypass node access',
       'access files overview',
+      'administer site configuration',
     ]);
     $this->drupalLogin($account);
 
@@ -75,6 +76,10 @@ class DeleteNodeWithMediaAndFile extends IslandoraFunctionalTestBase {
     ]);
     $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 <shriram1056@outlook.com>
Date: Fri, 25 Nov 2022 13:28:24 -0400
Subject: [PATCH 18/32] fixed log message

---
 islandora.module | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/islandora.module b/islandora.module
index b651f291..05e18c4a 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 <lefaive@gmail.com>
Date: Wed, 30 Nov 2022 10:07:19 -0400
Subject: [PATCH 19/32] 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 c02d7c16..8fe708ed 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 7deecc69..1ac77eec 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 b498ba66..a9fd4584 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 <lefaive@gmail.com>
Date: Wed, 30 Nov 2022 10:51:05 -0400
Subject: [PATCH 20/32] 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 1ac77eec..3dcae297 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 a9fd4584..2c819101 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 <jason@peaceworks.ca>
Date: Thu, 1 Dec 2022 14:24:35 -0600
Subject: [PATCH 21/32] 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 0209505d..3c69bddd 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 <jason@peaceworks.ca>
Date: Thu, 1 Dec 2022 16:13:40 -0600
Subject: [PATCH 22/32] 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 5b5446d1..9814820e 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 <lefaive@gmail.com>
Date: Thu, 1 Dec 2022 19:05:49 -0400
Subject: [PATCH 23/32] 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 eebdd9ab..29b40894 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 <saravananshriram80@gmail.com>
Date: Fri, 2 Dec 2022 16:36:04 -0400
Subject: [PATCH 24/32] 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 047006bf..840dc294 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 05e18c4a..64b65ca8 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 00000000..0a29e56e
--- /dev/null
+++ b/islandora.post_update.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Post updates.
+ */
+
+/**
+ * Set default value for delete_media_and_files field in settings.
+ */
+function islandora_post_update_delete_media_and_files() {
+  $config_factory = \Drupal::configFactory();
+  $config = $config_factory->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 a65ab82f..90e0b420 100644
--- a/src/Form/IslandoraSettingsForm.php
+++ b/src/Form/IslandoraSettingsForm.php
@@ -205,7 +205,7 @@ class IslandoraSettingsForm extends ConfigFormBase {
     $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 <lefaive@gmail.com>
Date: Tue, 6 Dec 2022 19:48:55 -0400
Subject: [PATCH 25/32] 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 cc4b5e94..c2a2fbc3 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 @@ class IIIFManifest extends StylePluginBase {
             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 <lefaive@gmail.com>
Date: Fri, 9 Dec 2022 11:41:36 -0400
Subject: [PATCH 26/32] 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 683f3e8b..2e0d226e 100644
--- a/src/EventGenerator/EmitEvent.php
+++ b/src/EventGenerator/EmitEvent.php
@@ -157,6 +157,10 @@ abstract class EmitEvent extends ConfigurableActionBase implements ContainerFact
 
       $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 b22201e1..129af994 100644
--- a/src/Plugin/Action/AbstractGenerateDerivative.php
+++ b/src/Plugin/Action/AbstractGenerateDerivative.php
@@ -60,6 +60,13 @@ class AbstractGenerateDerivative extends AbstractGenerateDerivativeBase {
       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 41f87101226ec466ba369dcd3b98b42255dd48da Mon Sep 17 00:00:00 2001
From: Rosie Le Faive <lefaive@gmail.com>
Date: Tue, 13 Dec 2022 16:43:06 -0400
Subject: [PATCH 27/32] 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 2e0d226e..fd33fd99 100644
--- a/src/EventGenerator/EmitEvent.php
+++ b/src/EventGenerator/EmitEvent.php
@@ -14,6 +14,7 @@ use Drupal\Core\Session\AccountInterface;
 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 @@ abstract class EmitEvent extends ConfigurableActionBase implements ContainerFact
 
       $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 @@ abstract class EmitEvent extends ConfigurableActionBase implements ContainerFact
         $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 00000000..66f63606
--- /dev/null
+++ b/src/Exception/IslandoraDerivativeException.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Drupal\islandora\Exception;
+
+/**
+ * Islandora exceptions.
+ *
+ * @package islandora
+ */
+class IslandoraDerivativeException extends \RuntimeException
+{
+}
diff --git a/src/Plugin/Action/AbstractGenerateDerivative.php b/src/Plugin/Action/AbstractGenerateDerivative.php
index 129af994..339d1d87 100644
--- a/src/Plugin/Action/AbstractGenerateDerivative.php
+++ b/src/Plugin/Action/AbstractGenerateDerivative.php
@@ -5,6 +5,7 @@ namespace Drupal\islandora\Plugin\Action;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
+use Drupal\islandora\Exception\IslandoraDerivativeException;
 
 /**
  * Emits a Node event.
@@ -64,7 +65,7 @@ class AbstractGenerateDerivative extends AbstractGenerateDerivativeBase {
     // 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;
+      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 <lefaive@gmail.com>
Date: Tue, 13 Dec 2022 17:12:44 -0400
Subject: [PATCH 28/32] 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 66f63606..7efe4773 100644
--- a/src/Exception/IslandoraDerivativeException.php
+++ b/src/Exception/IslandoraDerivativeException.php
@@ -7,6 +7,5 @@ namespace Drupal\islandora\Exception;
  *
  * @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 339d1d87..b44db477 100644
--- a/src/Plugin/Action/AbstractGenerateDerivative.php
+++ b/src/Plugin/Action/AbstractGenerateDerivative.php
@@ -65,7 +65,7 @@ class AbstractGenerateDerivative extends AbstractGenerateDerivativeBase {
     // 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 <lefaive@gmail.com>
Date: Tue, 13 Dec 2022 19:22:12 -0400
Subject: [PATCH 29/32] Use new syntax for filehash.

---
 islandora.module | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/islandora.module b/islandora.module
index 5b5446d1..faf24fdc 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 <lefaive@gmail.com>
Date: Wed, 14 Dec 2022 10:39:01 -0400
Subject: [PATCH 30/32] Update dependencies.

---
 composer.json | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/composer.json b/composer.json
index 43533a69..c1bfaa2d 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 <lefaive@gmail.com>
Date: Wed, 14 Dec 2022 10:39:37 -0400
Subject: [PATCH 31/32] Sort dependencies.

---
 composer.json | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/composer.json b/composer.json
index c1bfaa2d..0b443c02 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 <lefaive@gmail.com>
Date: Wed, 14 Dec 2022 13:54:33 -0400
Subject: [PATCH 32/32] 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 e0420fe8..a6e06774 100644
--- a/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php
+++ b/modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php
@@ -51,7 +51,7 @@ class GenerateImageDerivativeFile extends AbstractGenerateDerivativeMediaFile {
       '#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.'),