Browse Source

Merge remote-tracking branch 'origin/2.x' into fix/polymorphic-call

pull/923/head
Adam Vessey 2 years ago
parent
commit
88c99b0a20
No known key found for this signature in database
GPG Key ID: 89B39535BF6D0D39
  1. 24
      composer.json
  2. 1
      config/install/islandora.settings.yml
  3. 5
      config/schema/islandora.schema.yml
  4. 3
      css/islandora.css
  5. 5
      islandora.libraries.yml
  6. 198
      islandora.module
  7. 16
      islandora.post_update.php
  8. 21
      modules/islandora_core_feature/config/install/filehash.settings.yml
  9. 238
      modules/islandora_core_feature/config/install/views.view.file_checksum.yml
  10. 6
      modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php
  11. 31
      modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php
  12. 18
      src/Controller/ManageMediaController.php
  13. 19
      src/Controller/ManageMembersController.php
  14. 3
      src/Controller/MediaSourceController.php
  15. 5
      src/EventGenerator/EmitEvent.php
  16. 11
      src/Exception/IslandoraDerivativeException.php
  17. 10
      src/Form/IslandoraSettingsForm.php
  18. 4
      src/MediaSource/MediaSourceService.php
  19. 8
      src/Plugin/Action/AbstractGenerateDerivative.php
  20. 17
      src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php
  21. 8
      src/Plugin/views/filter/NodeHasMediaUse.php
  22. 104
      tests/src/Functional/DeleteNodeWithMediaAndFile.php

24
composer.json

@ -14,22 +14,22 @@
}
],
"require": {
"drupal/context": "^4.0@beta",
"drupal/search_api": "~1.8",
"islandora/jsonld": "^2",
"stomp-php/stomp-php": "4.* || ^5",
"drupal/jwt": "^1.0.0-beta5",
"drupal/filehash": "^1.1 || ^2",
"drupal/prepopulate" : "^2.2",
"drupal/eva" : "^2.0",
"drupal/context": "^4",
"drupal/ctools": "^3.8 || ^4",
"drupal/eva" : "^3.0",
"drupal/features" : "^3.7",
"drupal/migrate_plus" : "^5.1",
"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",

1
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: []

5
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'

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: {}

198
islandora.module

@ -27,6 +27,8 @@ use Drupal\file\FileInterface;
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().
@ -181,7 +183,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;
}
@ -331,6 +334,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);
}
}
/**
@ -515,7 +709,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;

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

21
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: true
original: true
dedupe_original: false
mime_types: { }

238
modules/islandora_core_feature/config/install/views.view.file_checksum.yml

@ -1,14 +1,15 @@
langcode: en
status: true
dependencies:
enforced:
module:
- islandora_core_feature
module:
- file
- filehash
- rest
- serialization
- user
enforced:
module:
- islandora_core_feature
id: file_checksum
label: 'File Checksum'
module: views
@ -16,71 +17,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 +46,7 @@ display:
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
trim_whitespace: true
alt: ''
rel: ''
link_class: ''
@ -106,7 +60,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 +76,120 @@ 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
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:
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: perm
options:
perm: 'view checksums'
cache:
type: tag
options: { }
empty: { }
relationships: { }
sorts: { }
arguments:
fid:
id: fid
@ -137,6 +198,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 +215,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 +228,47 @@ 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
- user.permissions
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 +278,19 @@ display:
type: data_field
options:
field_options: { }
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
- jwt_auth
@ -205,7 +298,10 @@ display:
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- request_format
- url
- user.permissions
tags: { }

6
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);

31
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;
}
@ -34,9 +36,30 @@ 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'),
'#default_value' => $this->configuration['destination_field_name'],
'#description' => $this->t('This Action stores the derivative in an
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.'),
];
$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;
}

18
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;
/**
@ -25,7 +26,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 +34,21 @@ class ManageMediaController extends ManageMembersController {
$field,
['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.", [
'@field' => $field,
]),
'manage_link' => $manage_link,
'add_media' => $add_media_list,
];
}
/**

19
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;
@ -88,7 +89,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 +98,21 @@ class ManageMembersController extends EntityController {
$field,
['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.", [
'@field' => $field,
]),
'manage_link' => $manage_link,
'add_node' => $add_node_list,
];
}
/**

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

5
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;
@ -168,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());

11
src/Exception/IslandoraDerivativeException.php

@ -0,0 +1,11 @@
<?php
namespace Drupal\islandora\Exception;
/**
* Islandora exceptions.
*
* @package islandora
*/
class IslandoraDerivativeException extends \RuntimeException {
}

10
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);

4
src/MediaSource/MediaSourceService.php

@ -276,8 +276,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");
@ -357,8 +357,8 @@ class MediaSourceService {
'uri' => $content_location,
'filename' => $this->fileSystem->basename($content_location),
'filemime' => $mimetype,
'status' => FileInterface::STATUS_PERMANENT,
]);
$file->setPermanent();
// Validate file extension.
$bundle = $media->bundle();

8
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.
@ -60,6 +61,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()) {
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 = [
'node' => $entity->id(),
'media_type' => $this->configuration['destination_media_type'],

17
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",
@ -98,15 +101,23 @@ class AbstractGenerateDerivativeMediaFile extends AbstractGenerateDerivativeBase
$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'] = [

8
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;
}
/**

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