Browse Source

Media multifile (#756)

* Syntax

* Formatting

* Adds files to existing media

* added dir creation

* added dependency

* added dependency

* pulled install

* coder stuff

* implicit schema

* added delete Action

* coder

* altered delete function

* Update composer.json

* Update islandora.info.yml

* Update AbstractGenerateDerivativeMediaFile.php

* Update composer.json

* Update composer.json

* Update MediaSourceHasMimetype.php

double semi colon

Co-authored-by: Alan Stanley <astanley@upei.ca>
Co-authored-by: Alan Stanley <alan@agile.humanities.ca>
pull/797/head
Alan Stanley 4 years ago committed by GitHub
parent
commit
ad05b37d08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      composer.json
  2. 1
      islandora.info.yml
  3. 22
      islandora.module
  4. 15
      islandora.routing.yml
  5. 43
      modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php
  6. 13
      modules/islandora_text_extraction/islandora_text_extraction.routing.yml
  7. 120
      modules/islandora_text_extraction/src/Controller/MediaSourceController.php
  8. 103
      modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivativeFile.php
  9. 56
      src/Controller/MediaSourceController.php
  10. 36
      src/Form/ConfirmDeleteMediaAndFile.php
  11. 316
      src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php
  12. 89
      src/Plugin/Condition/MediaSourceHasMimetype.php
  13. 58
      src/Plugin/ContextReaction/DerivativeFileReaction.php

6
composer.json

@ -28,8 +28,10 @@
"drupal/migrate_source_csv" : "^2.1", "drupal/migrate_source_csv" : "^2.1",
"drupal/token" : "^1.3", "drupal/token" : "^1.3",
"drupal/flysystem" : "^1.0", "drupal/flysystem" : "^1.0",
"drupal/file_replace": "^1.1", "islandora/crayfish-commons": "dev-dev",
"islandora/crayfish-commons": "dev-dev" "drupal/hook_post_action" : "^1.0",
"drupal/file_replace": "^1.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6", "phpunit/phpunit": "^6",

1
islandora.info.yml

@ -31,4 +31,5 @@ dependencies:
- content_translation - content_translation
- flysystem - flysystem
- token - token
- hook_post_action
- file_replace - file_replace

22
islandora.module

@ -107,7 +107,6 @@ function islandora_node_delete(NodeInterface $node) {
*/ */
function islandora_media_insert(MediaInterface $media) { function islandora_media_insert(MediaInterface $media) {
$utils = \Drupal::service('islandora.utils'); $utils = \Drupal::service('islandora.utils');
// Execute index reactions. // Execute index reactions.
$utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\IndexReaction', $media); $utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\IndexReaction', $media);
@ -137,7 +136,6 @@ function islandora_media_update(MediaInterface $media) {
// Execute index reactions. // Execute index reactions.
$utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\IndexReaction', $media); $utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\IndexReaction', $media);
// Does it have a source field? // Does it have a source field?
$source_field = $media_source_service->getSourceFieldName($media->bundle()); $source_field = $media_source_service->getSourceFieldName($media->bundle());
if (empty($source_field)) { if (empty($source_field)) {
@ -148,7 +146,6 @@ function islandora_media_update(MediaInterface $media) {
if ($media->get($source_field)->equals($media->original->get($source_field))) { if ($media->get($source_field)->equals($media->original->get($source_field))) {
return; return;
} }
// If it has a parent node... // If it has a parent node...
$node = $utils->getParentNode($media); $node = $utils->getParentNode($media);
if ($node) { if ($node) {
@ -158,6 +155,7 @@ function islandora_media_update(MediaInterface $media) {
$node, $node,
$media $media
); );
$utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\DerivativeFileReaction', $media);
} }
} }
@ -171,6 +169,19 @@ function islandora_media_delete(MediaInterface $media) {
$utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\DeleteReaction', $media); $utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\DeleteReaction', $media);
} }
/**
* Implements hook_ENTITYTYPE_postsave().
*/
function islandora_media_postsave(EntityInterface $media, $op) {
$utils = \Drupal::service('islandora.utils');
// Add derived file to the media.
if ($op == 'insert') {
$utils->executeMediaReactions('\Drupal\islandora\Plugin\ContextReaction\DerivativeFileReaction', $media);
}
}
/** /**
* Implements hook_file_insert(). * Implements hook_file_insert().
*/ */
@ -274,10 +285,11 @@ function islandora_jsonld_alter_normalized_array(EntityInterface $entity, array
function islandora_entity_view_mode_alter(&$view_mode, EntityInterface $entity) { function islandora_entity_view_mode_alter(&$view_mode, EntityInterface $entity) {
// Change the view mode based on user input from a 'view_mode_alter' // Change the view mode based on user input from a 'view_mode_alter'
// ContextReaction. // ContextReaction.
$entity_type = $entity->getEntityType()->id();
$storage = \Drupal::service('entity_type.manager')->getStorage('entity_view_mode'); $storage = \Drupal::service('entity_type.manager')->getStorage('entity_view_mode');
$context_manager = \Drupal::service('context.manager'); $context_manager = \Drupal::service('context.manager');
$current_entity = \Drupal::routeMatch()->getParameter('node'); $current_entity = \Drupal::routeMatch()->getParameter($entity_type);
$current_id = ($current_entity instanceof NodeInterface) ? $current_entity->id() : NULL; $current_id = ($current_entity instanceof NodeInterface || $current_entity instanceof MediaInterface) ? $current_entity->id() : NULL;
if (isset($current_id) && $current_id == $entity->id()) { if (isset($current_id) && $current_id == $entity->id()) {
foreach ($context_manager->getActiveReactions('\Drupal\islandora\Plugin\ContextReaction\ViewModeAlterReaction') as $reaction) { foreach ($context_manager->getActiveReactions('\Drupal\islandora\Plugin\ContextReaction\ViewModeAlterReaction') as $reaction) {
// Construct the new view mode's machine name. // Construct the new view mode's machine name.

15
islandora.routing.yml

@ -58,6 +58,20 @@ islandora.media_source_put_to_node:
options: options:
_auth: ['basic_auth', 'cookie', 'jwt_auth'] _auth: ['basic_auth', 'cookie', 'jwt_auth']
islandora.attach_file_to_media:
path: '/media/add_derivative/{media}/{destination_field}'
defaults:
_controller: '\Drupal\islandora\Controller\MediaSourceController::attachToMedia'
methods: [GET, PUT]
requirements:
_custom_access: '\Drupal\islandora\Controller\MediaSourceController::attachToMediaAccess'
options:
_auth: ['basic_auth', 'cookie', 'jwt_auth']
no_cache: 'TRUE'
parameters:
media:
type: entity:media
islandora.confirm_delete_media_and_file: islandora.confirm_delete_media_and_file:
path: '/media/delete_with_files' path: '/media/delete_with_files'
defaults: defaults:
@ -65,3 +79,4 @@ islandora.confirm_delete_media_and_file:
requirements: requirements:
_permission: 'administer media+delete any media' _permission: 'administer media+delete any media'

43
modules/islandora_image/src/Plugin/Action/GenerateImageDerivativeFile.php

@ -0,0 +1,43 @@
<?php
namespace Drupal\islandora_image\Plugin\Action;
use Drupal\Core\Form\FormStateInterface;
use Drupal\islandora\Plugin\Action\AbstractGenerateDerivativeMediaFile;
/**
* Emits a Node for generating derivatives event.
*
* @Action(
* id = "generate_image_derivative_file",
* label = @Translation("Generate an Image Derivative for Media Attachment"),
* type = "media"
* )
*/
class GenerateImageDerivativeFile extends AbstractGenerateDerivativeMediaFile {
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
$config = parent::defaultConfiguration();
$config['path'] = '[date:custom:Y]-[date:custom:m]/[media:mid]-ImageService.jpg';
$config['mimetype'] = 'application/xml';
$config['queue'] = 'islandora-connector-houdini';
$config['destination_media_type'] = 'file';
$config['scheme'] = file_default_scheme();
return $config;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['mimetype']['#description'] = t('Mimetype to convert to (e.g. application/xml, etc...)');
$form['mimetype']['#value'] = 'image/jpeg';
$form['mimetype']['#type'] = 'hidden';
return $form;
}
}

13
modules/islandora_text_extraction/islandora_text_extraction.routing.yml

@ -0,0 +1,13 @@
islandora_text_extraction.attach_file_to_media:
path: '/media/add_ocr/{media}/{destination_field}/{destination_text_field}'
defaults:
_controller: '\Drupal\islandora_text_extraction\Controller\MediaSourceController::attachToMedia'
methods: [GET, PUT]
requirements:
_custom_access: '\Drupal\islandora\Controller\MediaSourceController::attachToMediaAccess'
options:
_auth: ['basic_auth', 'cookie', 'jwt_auth']
no_cache: 'TRUE'
parameters:
media:
type: entity:media

120
modules/islandora_text_extraction/src/Controller/MediaSourceController.php

@ -0,0 +1,120 @@
<?php
namespace Drupal\islandora_text_extraction\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\media\Entity\Media;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\File\FileSystem;
/**
* Class MediaSourceController.
*/
class MediaSourceController extends ControllerBase {
/**
* Adds file to existing media.
*
* @param Drupal\media\Entity\Media $media
* The media to which file is added.
* @param string $destination_field
* The name of the media field to add file reference.
* @param string $destination_text_field
* The name of the media field to add file reference.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\Response
* 201 on success with a Location link header.
*
* @throws \Drupal\Core\Entity\EntityStorageException
* @throws \Drupal\Core\TypedData\Exception\ReadOnlyException
*/
/**
* File system service.
*
* @var \Drupal\Core\File\FileSystem
*/
protected $fileSystem;
/**
* MediaSourceController constructor.
*
* @param \Drupal\Core\File\FileSystem $fileSystem
* Filesystem service.
*/
public function __construct(FileSystem $fileSystem) {
$this->fileSystem = $fileSystem;
}
/**
* Controller's create method for dependency injection.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The App Container.
*
* @return \Drupal\islandora\Controller\MediaSourceController
* Controller instance.
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('file_system')
);
}
/**
* Attaches incoming file to existing media.
*
* @param \Drupal\media\Entity\Media $media
* Media to hold file.
* @param string $destination_field
* Media field to hold file.
* @param string $destination_text_field
* Media field to hold extracted text.
* @param \Symfony\Component\HttpFoundation\Request $request
* HTTP Request from Karaf.
*
* @return \Symfony\Component\HttpFoundation\Response
* HTTP response.
*
* @throws \Drupal\Core\Entity\EntityStorageException
* @throws \Drupal\Core\TypedData\Exception\ReadOnlyException
*/
public function attachToMedia(
Media $media,
string $destination_field,
string $destination_text_field,
Request $request) {
$content_location = $request->headers->get('Content-Location', "");
$contents = $request->getContent();
if ($contents) {
$directory = $this->fileSystem->dirname($content_location);
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
throw new HttpException(500, "The destination directory does not exist, could not be created, or is not writable");
}
$file = file_save_data($contents, $content_location, FILE_EXISTS_REPLACE);
if ($media->hasField($destination_field)) {
$media->{$destination_field}->setValue([
'target_id' => $file->id(),
]);
}
else {
$this->getLogger('islandora')->warning("Field $destination_field is not defined in Media Type {$media->bundle()}");
}
if ($media->hasField($destination_text_field)) {
$media->{$destination_text_field}->setValue(nl2br($contents));
}
else {
$this->getLogger('islandora')->warning("Field $destination_text_field is not defined in Media Type {$media->bundle()}");
}
$media->save();
}
// We'd only ever get here if testing the function with GET.
return new Response("<h1>Complete</h1>");
}
}

103
modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivativeFile.php

@ -0,0 +1,103 @@
<?php
namespace Drupal\islandora_text_extraction\Plugin\Action;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\islandora\Plugin\Action\AbstractGenerateDerivativeMediaFile;
/**
* Emits a Node for generating fits derivatives event.
*
* @Action(
* id = "generate_extracted_text_file",
* label = @Translation("Generate an Extracted Text derivative file"),
* type = "media"
* )
*/
class GenerateOCRDerivativeFile extends AbstractGenerateDerivativeMediaFile {
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
$config = parent::defaultConfiguration();
$config['path'] = '[date:custom:Y]-[date:custom:m]/[media:mid]-extracted_text.txt';
$config['mimetype'] = 'application/xml';
$config['queue'] = 'islandora-connector-ocr';
$config['destination_media_type'] = 'file';
$config['scheme'] = file_default_scheme();
$config['destination_text_field_name'] = '';
return $config;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$map = $this->entityFieldManager->getFieldMapByFieldType('text_long');
$file_fields = $map['media'];
$field_options = array_combine(array_keys($file_fields), array_keys($file_fields));
$form = parent::buildConfigurationForm($form, $form_state);
$form['mimetype']['#description'] = t('Mimetype to convert to (e.g. application/xml, etc...)');
$form['mimetype']['#value'] = 'text/plain';
$form['mimetype']['#type'] = 'hidden';
$position = array_search('destination_field_name', array_keys($form));
$first = array_slice($form, 0, $position);
$last = array_slice($form, count($form) - $position + 1);
$middle['destination_text_field_name'] = [
'#required' => TRUE,
'#type' => 'select',
'#options' => $field_options,
'#title' => $this->t('Destination Text field Name'),
'#default_value' => $this->configuration['destination_text_field_name'],
'#description' => $this->t('Text field on Media Type to hold extracted text.'),
];
$form = array_merge($first, $middle, $last);
unset($form['args']);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
$exploded_mime = explode('/', $form_state->getValue('mimetype'));
if ($exploded_mime[0] != 'text') {
$form_state->setErrorByName(
'mimetype',
t('Please enter file mimetype (e.g. application/xml.)')
);
}
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$this->configuration['destination_text_field_name'] = $form_state->getValue('destination_text_field_name');
}
/**
* Override this to return arbitrary data as an array to be json encoded.
*/
protected function generateData(EntityInterface $entity) {
$data = parent::generateData($entity);
$route_params = [
'media' => $entity->id(),
'destination_field' => $this->configuration['destination_field_name'],
'destination_text_field' => $this->configuration['destination_text_field_name'],
];
$data['destination_uri'] = Url::fromRoute('islandora_text_extraction.attach_file_to_media', $route_params)
->setAbsolute()
->toString();
return $data;
}
}

56
src/Controller/MediaSourceController.php

@ -7,6 +7,7 @@ use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection; use Drupal\Core\Database\Connection;
use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
use Drupal\media\Entity\Media;
use Drupal\media\MediaInterface; use Drupal\media\MediaInterface;
use Drupal\media\MediaTypeInterface; use Drupal\media\MediaTypeInterface;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
@ -210,4 +211,59 @@ class MediaSourceController extends ControllerBase {
return AccessResult::allowedIf($node->access('update', $account) && $account->hasPermission('create media')); return AccessResult::allowedIf($node->access('update', $account) && $account->hasPermission('create media'));
} }
/**
* Adds file to existing media.
*
* @param Drupal\media\Entity\Media\Media $media
* The media to which file is added.
* @param string $destination_field
* The name of the media field to add file reference.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\Response
* 201 on success with a Location link header.
*
* @throws \Drupal\Core\Entity\EntityStorageException
* @throws \Drupal\Core\TypedData\Exception\ReadOnlyException
*/
public function attachToMedia(
Media $media,
string $destination_field,
Request $request) {
$content_location = $request->headers->get('Content-Location', "");
$contents = $request->getContent();
if ($contents) {
$file = file_save_data($contents, $content_location, FILE_EXISTS_REPLACE);
if ($media->hasField($destination_field)) {
$media->{$destination_field}->setValue([
'target_id' => $file->id(),
]);
$media->save();
}
else {
$this->getLogger('islandora')->warning("Field $destination_field is not defined in Media Type {$media->bundle()}");
}
}
// Should only see this with a GET request for testing.
return new Response("<h1>Complete</h1>");
}
/**
* Checks for permissions to update a node and update media.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Account for user making the request.
* @param \Drupal\Core\Routing\RouteMatch $route_match
* Route match to get Node from url params.
*
* @return \Drupal\Core\Access\AccessResultInterface
* Access result.
*/
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'));
}
} }

36
src/Form/ConfirmDeleteMediaAndFile.php

@ -2,6 +2,7 @@
namespace Drupal\islandora\Form; namespace Drupal\islandora\Form;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Form\DeleteMultipleForm; use Drupal\Core\Entity\Form\DeleteMultipleForm;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
@ -9,6 +10,7 @@ use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory; use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\islandora\MediaSource\MediaSourceService; use Drupal\islandora\MediaSource\MediaSourceService;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
@ -39,12 +41,20 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
*/ */
protected $selection = []; protected $selection = [];
/**
* Entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, PrivateTempStoreFactory $temp_store_factory, MessengerInterface $messenger, MediaSourceService $media_source_service, LoggerInterface $logger) { public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, PrivateTempStoreFactory $temp_store_factory, MessengerInterface $messenger, MediaSourceService $media_source_service, LoggerInterface $logger) {
$this->currentUser = $current_user; $this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager; $this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->tempStore = $temp_store_factory->get('media_and_file_delete_confirm'); $this->tempStore = $temp_store_factory->get('media_and_file_delete_confirm');
$this->messenger = $messenger; $this->messenger = $messenger;
$this->mediaSourceService = $media_source_service; $this->mediaSourceService = $media_source_service;
@ -58,6 +68,7 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
return new static( return new static(
$container->get('current_user'), $container->get('current_user'),
$container->get('entity_type.manager'), $container->get('entity_type.manager'),
$container->get('entity_field.manager'),
$container->get('tempstore.private'), $container->get('tempstore.private'),
$container->get('messenger'), $container->get('messenger'),
$container->get('islandora.media_source_service'), $container->get('islandora.media_source_service'),
@ -115,15 +126,24 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
continue; continue;
} }
// Check for files. // Check for files.
$source_field = $this->mediaSourceService->getSourceFieldName($entity->bundle()); $fields = $this->entityFieldManager->getFieldDefinitions('media', $entity->bundle());
foreach ($entity->get($source_field)->referencedEntities() as $file) { $files = [];
if (!$file->access('delete', $this->currentUser)) { foreach ($fields as $field) {
$inaccessible_entities[] = $file; $type = $field->getType();
continue; if ($type == 'file' || $type == 'image') {
$target_id = $entity->get($field->getName())->target_id;
$file = File::load($target_id);
if ($file) {
if (!$file->access('delete', $this->currentUser)) {
$inaccessible_entities[] = $file;
continue;
}
$delete_files[$file->id()] = $file;
$total_count++;
}
} }
$delete_files[$file->id()] = $file;
$total_count++;
} }
foreach ($selected_langcodes as $langcode) { foreach ($selected_langcodes as $langcode) {
// We're only working with media, which are translatable. // We're only working with media, which are translatable.
$entity = $entity->getTranslation($langcode); $entity = $entity->getTranslation($langcode);

316
src/Plugin/Action/AbstractGenerateDerivativeMediaFile.php

@ -0,0 +1,316 @@
<?php
namespace Drupal\islandora\Plugin\Action;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\islandora\EventGenerator\EmitEvent;
use Drupal\islandora\EventGenerator\EventGeneratorInterface;
use Drupal\islandora\IslandoraUtils;
use Drupal\islandora\MediaSource\MediaSourceService;
use Drupal\jwt\Authentication\Provider\JwtAuth;
use Drupal\token\Token;
use Stomp\StatefulStomp;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Emits a Node for generating derivatives event.
*
* @Action(
* id = "generate_derivative_file",
* label = @Translation("Generate a Derivative File for Media Attachment"),
* type = "media"
* )
*/
class AbstractGenerateDerivativeMediaFile extends EmitEvent {
/**
* Islandora utility functions.
*
* @var \Drupal\islandora\IslandoraUtils
*/
protected $utils;
/**
* Media source service.
*
* @var \Drupal\islandora\MediaSource\MediaSourceService
*/
protected $mediaSource;
/**
* Token replacement service.
*
* @var \Drupal\token\Token
*/
protected $token;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManager
*/
protected $entityFieldManager;
/**
* Constructs a EmitEvent action.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Session\AccountInterface $account
* Current user.
* @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
* Entity type manager.
* @param \Drupal\islandora\EventGenerator\EventGeneratorInterface $event_generator
* EventGenerator service to serialize AS2 events.
* @param \Stomp\StatefulStomp $stomp
* Stomp client.
* @param \Drupal\jwt\Authentication\Provider\JwtAuth $auth
* JWT Auth client.
* @param \Drupal\islandora\IslandoraUtils $utils
* Islandora utility functions.
* @param \Drupal\islandora\MediaSource\MediaSourceService $media_source
* Media source service.
* @param \Drupal\token\Token $token
* Token service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* Field Manager service.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
AccountInterface $account,
EntityTypeManager $entity_type_manager,
EventGeneratorInterface $event_generator,
StatefulStomp $stomp,
JwtAuth $auth,
IslandoraUtils $utils,
MediaSourceService $media_source,
Token $token,
EntityFieldManagerInterface $entity_field_manager
) {
parent::__construct(
$configuration,
$plugin_id,
$plugin_definition,
$account,
$entity_type_manager,
$event_generator,
$stomp,
$auth
);
$this->utils = $utils;
$this->mediaSource = $media_source;
$this->token = $token;
$this->entityFieldManager = $entity_field_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('current_user'),
$container->get('entity_type.manager'),
$container->get('islandora.eventgenerator'),
$container->get('islandora.stomp'),
$container->get('jwt.authentication.jwt'),
$container->get('islandora.utils'),
$container->get('islandora.media_source_service'),
$container->get('token'),
$container->get('entity_field.manager')
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
$uri = 'http://pcdm.org/use#OriginalFile';
return [
'queue' => 'islandora-connector-houdini',
'event' => 'Generate Derivative',
'source_term_uri' => $uri,
'mimetype' => '',
'args' => '',
'path' => '[date:custom:Y]-[date:custom:m]/[media:mid].bin',
'source_field_name' => 'field_media_file',
'destination_field_name' => '',
];
}
/**
* Override this to return arbitrary data as an array to be json encoded.
*/
protected function generateData(EntityInterface $entity) {
$data = parent::generateData($entity);
if (get_class($entity) != 'Drupal\media\Entity\Media') {
return;
}
$source_file = $this->mediaSource->getSourceFile($entity);
if (!$source_file) {
throw new \RuntimeException("Could not locate source file for media {$entity->id()}", 500);
}
$data['source_uri'] = $this->utils->getDownloadUrl($source_file);
$route_params = [
'media' => $entity->id(),
'destination_field' => $this->configuration['destination_field_name'],
];
$data['destination_uri'] = Url::fromRoute('islandora.attach_file_to_media', $route_params)
->setAbsolute()
->toString();
$token_data = [
'media' => $entity,
];
$destination_field = $this->configuration['destination_field_name'];
$field = \Drupal::entityTypeManager()
->getStorage('field_storage_config')
->load("media.$destination_field");
$scheme = $field->getSetting('uri_scheme');
$path = $this->token->replace($data['path'], $token_data);
$data['file_upload_uri'] = $scheme . '://' . $path;
$allowed = [
'queue',
'event',
'args',
'source_uri',
'destination_uri',
'file_upload_uri',
'mimetype',
];
foreach ($data as $key => $value) {
if (!in_array($key, $allowed)) {
unset($data[$key]);
}
}
return $data;
}
/**
* {@inheritdoc}
*/
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);
$form['event']['#disabled'] = 'disabled';
$form['destination_field_name'] = [
'#required' => TRUE,
'#type' => 'select',
'#options' => $file_options,
'#title' => $this->t('Destination File field Name'),
'#default_value' => $this->configuration['destination_field_name'],
'#description' => $this->t('File field on Media Type to hold derivative. Cannot be the same as source'),
];
$form['args'] = [
'#type' => 'textfield',
'#title' => t('Additional arguments'),
'#default_value' => $this->configuration['args'],
'#rows' => '8',
'#description' => t('Additional command line arguments'),
];
$form['mimetype'] = [
'#type' => 'textfield',
'#title' => t('Mimetype'),
'#default_value' => $this->configuration['mimetype'],
'#required' => TRUE,
'#rows' => '8',
'#description' => t('Mimetype to convert to (e.g. image/jpeg, video/mp4, etc...)'),
];
$form['path'] = [
'#type' => 'textfield',
'#title' => t('File path'),
'#default_value' => $this->configuration['path'],
'#description' => t('Path within the upload destination where files will be stored. Includes the filename and optional extension.'),
];
$form['queue'] = [
'#type' => 'textfield',
'#title' => t('Queue name'),
'#default_value' => $this->configuration['queue'],
'#description' => t('Queue name to send along to help routing events, CHANGE WITH CARE. Defaults to :queue', [
':queue' => $this->defaultConfiguration()['queue'],
]),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
$mimetype = $form_state->getValue('mimetype');
$exploded = explode('/', $form_state->getValue('mimetype'));
if (count($exploded) != 2) {
$form_state->setErrorByName(
'mimetype',
t('Please enter a mimetype (e.g. image/jpeg, video/mp4, audio/mp3, etc...)')
);
}
if (empty($exploded[1])) {
$form_state->setErrorByName(
'mimetype',
t('Please enter a mimetype (e.g. image/jpeg, video/mp4, audio/mp3, etc...)')
);
}
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$this->configuration['mimetype'] = $form_state->getValue('mimetype');
$this->configuration['args'] = $form_state->getValue('args');
$this->configuration['scheme'] = $form_state->getValue('scheme');
$this->configuration['path'] = trim($form_state->getValue('path'), '\\/');
$this->configuration['destination_field_name'] = $form_state->getValue('destination_field_name');
}
/**
* Find a media_type by id and return it or nothing.
*
* @param string $entity_id
* The media type.
*
* @return \Drupal\Core\Entity\EntityInterface|string
* Return the loaded entity or nothing.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* Thrown by getStorage() if the entity type doesn't exist.
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* Thrown by getStorage() if the storage handler couldn't be loaded.
*/
protected function getEntityById($entity_id) {
$entity_ids = $this->entityTypeManager->getStorage('media_type')
->getQuery()->condition('id', $entity_id)->execute();
$id = reset($entity_ids);
if ($id !== FALSE) {
return $this->entityTypeManager->getStorage('media_type')->load($id);
}
return '';
}
}

89
src/Plugin/Condition/MediaSourceHasMimetype.php

@ -0,0 +1,89 @@
<?php
namespace Drupal\islandora\Plugin\Condition;
use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;
/**
* Provides a 'Media Source' condition.
*
* @Condition(
* id = "media_source_mimetype",
* label = @Translation("Media Source Mimetype"),
* context = {
* "media" = @ContextDefinition("entity:media", required = FALSE, label = @Translation("Media"))
* }
* )
*/
class MediaSourceHasMimetype extends ConditionPluginBase {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['mimetype'] = [
'#title' => $this->t('Source Media Mimetype'),
'#type' => 'textfield',
'#default_value' => $this->configuration['mimetype'],
];
return parent::buildConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['mimetype'] = $form_state->getValue('mimetype');
parent::submitConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function evaluate() {
foreach ($this->getContexts() as $context) {
if ($context->hasContextValue()) {
$entity = $context->getContextValue();
$mid = $entity->id();
if ($mid && !empty($this->configuration['mimetype'])) {
$source = $entity->getSource();
$source_file = File::load($source->getSourceFieldValue($entity));
if ($this->configuration['mimetype'] == $source_file->getMimeType()) {
return !$this->isNegated();
}
}
}
}
return $this->isNegated();
}
/**
* {@inheritdoc}
*/
public function summary() {
if (empty($this->configuration['mimetype'])) {
return $this->t('No mimetype are selected.');
}
return $this->t(
'Entity bundle in the list: @mimetype',
[
'@mimetype' => implode(', ', $this->configuration['field']),
]
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array_merge(
['mimetype' => []],
parent::defaultConfiguration()
);
}
}

58
src/Plugin/ContextReaction/DerivativeFileReaction.php

@ -0,0 +1,58 @@
<?php
namespace Drupal\islandora\Plugin\ContextReaction;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\islandora\Plugin\Action\AbstractGenerateDerivativeMediaFile;
use Drupal\islandora\PresetReaction\PresetReaction;
/**
* Derivative context reaction.
*
* @ContextReaction(
* id = "file_derivative",
* label = @Translation("Derive file For Existing Media")
* )
*/
class DerivativeFileReaction extends PresetReaction {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$actions = $this->actionStorage->loadByProperties(['type' => 'media']);
foreach ($actions as $action) {
$plugin = $action->getPlugin();
if ($plugin instanceof AbstractGenerateDerivativeMediaFile) {
$options[ucfirst($action->getType())][$action->id()] = $action->label();
}
}
$config = $this->getConfiguration();
$form['actions'] = [
'#title' => $this->t('Actions'),
'#description' => $this->t('Pre-configured actions to execute. Multiple actions may be selected by shift or ctrl clicking.'),
'#type' => 'select',
'#multiple' => TRUE,
'#options' => $options,
'#default_value' => isset($config['actions']) ? $config['actions'] : '',
'#size' => 15,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function execute(EntityInterface $entity = NULL) {
$config = $this->getConfiguration();
$action_ids = $config['actions'];
foreach ($action_ids as $action_id) {
$action = $this->actionStorage->load($action_id);
$action->execute([$entity]);
}
}
}
Loading…
Cancel
Save