Browse Source

Merge pull request #905 from shriram1056/dev

Delete content node along with its media and file
pull/916/head
Jordan Dukart 2 years ago committed by GitHub
parent
commit
023b24b5d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      config/install/islandora.settings.yml
  2. 5
      config/schema/islandora.schema.yml
  3. 3
      css/islandora.css
  4. 5
      islandora.libraries.yml
  5. 193
      islandora.module
  6. 16
      islandora.post_update.php
  7. 10
      src/Form/IslandoraSettingsForm.php
  8. 104
      tests/src/Functional/DeleteNodeWithMediaAndFile.php

1
config/install/islandora.settings.yml

@ -1,4 +1,5 @@
broker_url: 'tcp://localhost:61613' broker_url: 'tcp://localhost:61613'
jwt_expiry: '+2 hour' jwt_expiry: '+2 hour'
gemini_url: '' gemini_url: ''
delete_media_and_files: TRUE
gemini_pseudo_bundles: [] gemini_pseudo_bundles: []

5
config/schema/islandora.schema.yml

@ -14,6 +14,9 @@ islandora.settings:
jwt_expiry: jwt_expiry:
type: string type: string
label: 'How long JWTs should last before expiring.' label: 'How long JWTs should last before expiring.'
delete_media_and_files:
type: boolean
label: 'Node Delete with Media and Files'
upload_form_location: upload_form_location:
type: string type: string
label: 'Upload Form Location' label: 'Upload Form Location'
@ -166,7 +169,7 @@ condition.plugin.node_had_namespace:
pid_field: pid_field:
type: ignore type: ignore
label: 'PID field' label: 'PID field'
field.formatter.settings.islandora_image: field.formatter.settings.islandora_image:
type: field.formatter.settings.image type: field.formatter.settings.image
label: 'Islandora image field display format settings' label: 'Islandora image field display format settings'

3
css/islandora.css

@ -0,0 +1,3 @@
.container .islandora-media-items {
margin: 0;
}

5
islandora.libraries.yml

@ -0,0 +1,5 @@
islandora:
version: VERSION
css:
theme:
css/islandora.css: {}

193
islandora.module

@ -27,6 +27,8 @@ use Drupal\file\FileInterface;
use Drupal\taxonomy\TermInterface; use Drupal\taxonomy\TermInterface;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\serialization\Normalizer\CacheableNormalizerInterface; use Drupal\serialization\Normalizer\CacheableNormalizerInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\file\Entity\File;
/** /**
* Implements hook_help(). * Implements hook_help().
@ -331,6 +333,197 @@ 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 ($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) {
$medias = $utils->getMedia($form_state->getFormObject()->getEntity());
if (count($medias) != 0) {
$form['delete_associated_content'] = [
'#type' => 'checkbox',
'#title' => t('Delete all associated medias and nodes'),
];
$media_list = [];
foreach ($medias as $media) {
$media_list[] = $media->getName();
}
$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,
'#attributes' => ['class' => ['islandora-media-items']],
'#wrapper_attributes' => ['class' => ['container']],
'#attached' => [
'library' => [
'islandora/islandora',
],
],
];
$form['actions']['submit']['#submit'][] = 'islandora_object_delete_form_submit';
return $form;
}
}
}
return $form;
}
/**
* Implements a submit handler for the delete form.
*/
function islandora_object_delete_form_submit($form, FormStateInterface $form_state) {
$result = $form_state->getValues('delete_associated_content');
$utils = \Drupal::service('islandora.utils');
if ($result['delete_associated_content'] == 1) {
$node = $form_state->getFormObject()->getEntity();
$medias = $utils->getMedia($node);
$media_list = [];
$entity_field_manager = \Drupal::service('entity_field.manager');
$current_user = \Drupal::currentUser();
$logger = \Drupal::logger('logger.channel.islandora');
$messenger = \Drupal::messenger();
$delete_media = [];
$media_translations = [];
$media_files = [];
$entity_protected_medias = [];
$inaccessible_entities = [];
foreach ($medias as $id => $media) {
$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;
}
$media_files[$id][$file->id()] = $file;
}
}
}
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($media_translations[$id]);
}
elseif (!isset($delete_media[$id])) {
$media_translations[$id][] = $entity;
}
}
}
if ($delete_media) {
foreach ($delete_media as $id => $media) {
try {
$media->delete();
$media_list[] = $id;
$logger->notice('The media %label has been deleted.', [
'%label' => $media->label(),
]);
}
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) {
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];
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(),
]);
}
}
}
if ($inaccessible_entities) {
$messenger->addWarning("@count items have 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(
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)],
),
]),
],
];
$message = \Drupal::service('renderer')->renderPlain($build);
$messenger->deleteByType('status');
$messenger->addStatus($message);
}
} }
/** /**

16
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);
}

10
src/Form/IslandoraSettingsForm.php

@ -42,6 +42,7 @@ class IslandoraSettingsForm extends ConfigFormBase {
'year', 'year',
]; ];
const GEMINI_PSEUDO_FIELD = 'field_gemini_uri'; const GEMINI_PSEUDO_FIELD = 'field_gemini_uri';
const NODE_DELETE_MEDIA_AND_FILES = 'delete_media_and_files';
/** /**
* To list the available bundle types. * To list the available bundle types.
@ -201,6 +202,14 @@ class IslandoraSettingsForm extends ConfigFormBase {
$fedora_url = NULL; $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] = [ $form[self::FEDORA_URL] = [
'#type' => 'textfield', '#type' => 'textfield',
'#title' => $this->t('Fedora URL'), '#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_LOCATION, $form_state->getValue(self::UPLOAD_FORM_LOCATION))
->set(self::UPLOAD_FORM_ALLOWED_MIMETYPES, $form_state->getValue(self::UPLOAD_FORM_ALLOWED_MIMETYPES)) ->set(self::UPLOAD_FORM_ALLOWED_MIMETYPES, $form_state->getValue(self::UPLOAD_FORM_ALLOWED_MIMETYPES))
->set(self::GEMINI_PSEUDO, $new_pseudo_types) ->set(self::GEMINI_PSEUDO, $new_pseudo_types)
->set(self::NODE_DELETE_MEDIA_AND_FILES, $form_state->getValue(self::NODE_DELETE_MEDIA_AND_FILES))
->save(); ->save();
parent::submitForm($form, $form_state); parent::submitForm($form, $form_state);

104
tests/src/Functional/DeleteNodeWithMediaAndFile.php

@ -0,0 +1,104 @@
<?php
namespace Drupal\Tests\islandora\Functional;
/**
* Tests the Delete Node with Media.
*
* @group islandora
*/
class DeleteNodeWithMediaAndFile extends IslandoraFunctionalTestBase {
/**
* Tests delete Node and its assoicated media.
*/
public function testDeleteNodeWithMediaAndFile() {
$account = $this->drupalCreateUser([
'delete any media',
'create media',
'view media',
'bypass node access',
'access files overview',
'administer site configuration',
]);
$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();
$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");
$assert_session->pageTextContains('Media1');
$assert_session->pageTextContains('Media2');
$this->submitForm($delete, 'Delete');
$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');
}
}
Loading…
Cancel
Save