Compare commits

..

54 Commits

Author SHA1 Message Date
Rosie Le Faive b8f0b9c966
Allow NodeHasMediaUse view filter to work on views with node relationships. (#1010) 6 months ago
Akanksha Singh da47bcfb08
Node has Parent context does not explicitly check if the field exists. (#1019) 6 months ago
Rosie Le Faive 5e958a5e10 Allow application/xml in OCR Action. 6 months ago
Rosie Le Faive 3902cce0ac
Allow filehash 3 (#1016) 6 months ago
Aron Novak c80769580c
Do not have a fatal error on a missing action (#1014) 7 months ago
Adam 54206de712
Fix Functional Javascript CI tests (#1004) 7 months ago
Joe Corall 9b2661696d
Add hOCR functionality (#1006) 7 months ago
Alexander O'Neill 089a3654ba
Merge pull request #1007 from rosiel/2.x 7 months ago
Rosie Le Faive 263666f5fc Remove new_storage_type from form part 2. 7 months ago
Rosie Le Faive 95c2d6c0c9 Syntax. 7 months ago
Rosie Le Faive cde2c133e1 Update tests for D10.3's new field selector form. 7 months ago
Rosie Le Faive a2c31fcaad @adam-vessey's fix for drupalGet headers. 7 months ago
Rosie Le Faive 9ed3637339
Update islandora.module (#1008) 7 months ago
Rosie Le Faive 13bc15ea43 Last attempt to not pass translatables as button labels. 8 months ago
Rosie Le Faive 9f2277fc51 Exclude PHP 8.3 with Drupal 10.1. 8 months ago
Rosie Le Faive 89261c17ae Add some forgotten translateable markup. 8 months ago
Rosie Le Faive 3784def287 Tests use strings not translateable markup to select interface buttons. 8 months ago
Rosie Le Faive e30cdbf681 Update testing drupal and php versions 8 months ago
Rosie Le Faive 3065c87874
Remove Feature-ness of Islandora Core Feature. (#968) 11 months ago
Alan Stanley d0e0c29921
Issue 1000 (#1001) 11 months ago
Alan Stanley 28174c3ce4
Change to Boolean logic (#999) 11 months ago
ajstanley 4404dff246 reverting accidental commit 11 months ago
ajstanley c93c1ff940 change to Boolean logic 11 months ago
ajstanley b65881625a change to Boooean logic 11 months ago
ajstanley c149781da0 Merge branch '2.x' of https://github.com/Islandora/islandora into 2.x 11 months ago
Seth Shaw c6341649ca
Use FileUrlGeneratorInterface (#996) 12 months ago
Annie Oelschlager 4630439760
Merge pull request #986 from rosiel/coi 12 months ago
Rosie Le Faive 056695c79c
8.2 deprecations from tests (#995) 1 year ago
Rosie Le Faive 4b2b9b221b
Fix tests (#991) 1 year ago
Joe Corall f29fef2bac
Do not render the pdf_url metatag if there is no value (#985) 1 year ago
Adam 095e0ecf67
Update to use the new hook. (#992) 1 year ago
Rosie Le Faive d5556f445d
Add PHP 8.2 <strike>and Drupal 10.2</strike> to testing matrix (#987) 1 year ago
Rosie Le Faive 2c91dc6f58 syntax. 1 year ago
Rosie Le Faive 16617a9dd7 Composer suggest COI. 1 year ago
Rosie Le Faive c05236ac8c Add COI integration to IIIF module. 1 year ago
Rosie Le Faive 6cfaca36e7
Update src/Form/IslandoraSettingsForm.php 1 year ago
Rosie Le Faive f077af677b Add COI integration to islandora settings form. 1 year ago
Adam 572ffcf2e1
Fix up typo. (#984) 1 year ago
Alexander O'Neill f7a77820d3
Merge pull request #980 from rosiel/issue-975 1 year ago
Annie Oelschlager 58d1b37f11
Merge pull request #982 from Islandora/rosiel-patch-1 1 year ago
Rosie Le Faive 76eb4717a2
Specify fetch-depth during mirroring to gitlab. 1 year ago
Annie Oelschlager e2ec673017
Merge pull request #971 from rosiel/media-redirect 1 year ago
Rosie Le Faive d6e07491d2 UI text improvement. 1 year ago
Rosie Le Faive c2cd14cfd5 Add config option to redirect after media add. 1 year ago
Rosie Le Faive fdfdd87472 Add media save redirect. 1 year ago
Rosie Le Faive 84c6ca85d8 Remove extra file. 1 year ago
Rosie Le Faive 91253bef14 Declare httpClient variable. 1 year ago
dannylamb e3399d3968
Stripping out json metadata in the queue messages except for the ones… (#973) 1 year ago
aOelschlager fd8319b7b2
Merge pull request #977 from Islandora/revert-976-rosiel-patch-1 1 year ago
Rosie Le Faive 5d83504778
Revert "Revert gitlab mirror to checkout v1." 1 year ago
aOelschlager 33340c2722
Merge pull request #976 from Islandora/rosiel-patch-1 1 year ago
Rosie Le Faive d1357d347d
Revert gitlab mirror to checkout v1. 1 year ago
Rosie Le Faive 0408edb93f
Push tags to gitlab. (#974) 1 year ago
ajstanley b733713610 added additional exception 3 years ago
  1. 52
      .github/workflows/build-2.x.yml
  2. 5
      .github/workflows/gitlab-mirror.yml
  3. 6
      composer.json
  4. 1
      config/install/islandora.settings.yml
  5. 6
      config/schema/islandora.schema.yml
  6. 1
      islandora.info.yml
  7. 14
      islandora.install
  8. 24
      islandora.module
  9. 3
      islandora.tokens.inc
  10. 6
      modules/islandora_audio/tests/src/Functional/GenerateAudioDerivativeTest.php
  11. 100
      modules/islandora_core_feature/config/install/features.bundle.islandora.yml
  12. 0
      modules/islandora_core_feature/config/optional/core.entity_view_mode.media.source.yml
  13. 0
      modules/islandora_core_feature/config/optional/field.field.taxonomy_term.islandora_media_use.field_external_uri.yml
  14. 0
      modules/islandora_core_feature/config/optional/field.field.taxonomy_term.islandora_models.field_external_uri.yml
  15. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_file_size.yml
  16. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_height.yml
  17. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_audio_file.yml
  18. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_document.yml
  19. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_file.yml
  20. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_image.yml
  21. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_of.yml
  22. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_use.yml
  23. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_media_video_file.yml
  24. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_mime_type.yml
  25. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_original_name.yml
  26. 0
      modules/islandora_core_feature/config/optional/field.storage.media.field_width.yml
  27. 0
      modules/islandora_core_feature/config/optional/field.storage.node.field_member_of.yml
  28. 0
      modules/islandora_core_feature/config/optional/field.storage.node.field_model.yml
  29. 0
      modules/islandora_core_feature/config/optional/field.storage.node.field_weight.yml
  30. 0
      modules/islandora_core_feature/config/optional/field.storage.taxonomy_term.field_external_uri.yml
  31. 0
      modules/islandora_core_feature/config/optional/filehash.settings.yml
  32. 0
      modules/islandora_core_feature/config/optional/migrate_plus.migration.islandora_tags.yml
  33. 0
      modules/islandora_core_feature/config/optional/migrate_plus.migration_group.islandora.yml
  34. 0
      modules/islandora_core_feature/config/optional/rest.resource.entity.file.yml
  35. 0
      modules/islandora_core_feature/config/optional/rest.resource.entity.media.yml
  36. 0
      modules/islandora_core_feature/config/optional/rest.resource.entity.node.yml
  37. 0
      modules/islandora_core_feature/config/optional/rest.resource.entity.taxonomy_term.yml
  38. 0
      modules/islandora_core_feature/config/optional/system.action.delete_file_as_fedora_external_content.yml
  39. 0
      modules/islandora_core_feature/config/optional/system.action.delete_media_from_triplestore.yml
  40. 0
      modules/islandora_core_feature/config/optional/system.action.delete_node_from_fedora.yml
  41. 0
      modules/islandora_core_feature/config/optional/system.action.delete_node_from_triplestore.yml
  42. 0
      modules/islandora_core_feature/config/optional/system.action.delete_taxonomy_term_in_fedora.yml
  43. 0
      modules/islandora_core_feature/config/optional/system.action.delete_taxonomy_term_in_triplestore.yml
  44. 0
      modules/islandora_core_feature/config/optional/system.action.index_file_as_fedora_external_content.yml
  45. 0
      modules/islandora_core_feature/config/optional/system.action.index_media_in_fedora.yml
  46. 0
      modules/islandora_core_feature/config/optional/system.action.index_media_in_triplestore.yml
  47. 0
      modules/islandora_core_feature/config/optional/system.action.index_node_in_fedora.yml
  48. 0
      modules/islandora_core_feature/config/optional/system.action.index_node_in_triplestore.yml
  49. 0
      modules/islandora_core_feature/config/optional/system.action.index_taxonomy_term_in_fedora.yml
  50. 0
      modules/islandora_core_feature/config/optional/system.action.index_taxonomy_term_in_the_triplestore.yml
  51. 0
      modules/islandora_core_feature/config/optional/taxonomy.vocabulary.islandora_media_use.yml
  52. 0
      modules/islandora_core_feature/config/optional/taxonomy.vocabulary.islandora_models.yml
  53. 0
      modules/islandora_core_feature/config/optional/views.view.all_taxonomy_terms.yml
  54. 0
      modules/islandora_core_feature/config/optional/views.view.display_media.yml
  55. 0
      modules/islandora_core_feature/config/optional/views.view.file_checksum.yml
  56. 0
      modules/islandora_core_feature/config/optional/views.view.manage_members.yml
  57. 0
      modules/islandora_core_feature/config/optional/views.view.media_of.yml
  58. 0
      modules/islandora_core_feature/config/optional/views.view.non_fedora_files.yml
  59. 0
      modules/islandora_core_feature/config/optional/views.view.reorder_children.yml
  60. 16
      modules/islandora_core_feature/islandora_core_feature.features.yml
  61. 1
      modules/islandora_core_feature/islandora_core_feature.info.yml
  62. 15
      modules/islandora_iiif/README.md
  63. 10
      modules/islandora_iiif/config/optional/system.action.media_attributes_from_iiif_action.yml
  64. 18
      modules/islandora_iiif/config/schema/islandora_iiif.schema.yml
  65. 18
      modules/islandora_iiif/islandora_iiif.install
  66. 4
      modules/islandora_iiif/islandora_iiif.services.yml
  67. 17
      modules/islandora_iiif/src/Form/IslandoraIIIFConfigForm.php
  68. 153
      modules/islandora_iiif/src/IiifInfo.php
  69. 165
      modules/islandora_iiif/src/Plugin/Action/MediaAttributesFromIiif.php
  70. 248
      modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php
  71. 6
      modules/islandora_image/tests/src/Functional/GenerateImageDerivativeTest.php
  72. 5
      modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php
  73. 5
      modules/islandora_text_extraction/src/Plugin/Field/FieldFormatter/OcrTextFormatter.php
  74. 0
      modules/islandora_text_extraction_defaults/config/optional/core.entity_form_display.media.extracted_text.default.yml
  75. 0
      modules/islandora_text_extraction_defaults/config/optional/core.entity_view_display.media.extracted_text.default.yml
  76. 0
      modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_edited_text.yml
  77. 0
      modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_media_file.yml
  78. 0
      modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_media_of.yml
  79. 0
      modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_media_use.yml
  80. 0
      modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_mime_type.yml
  81. 0
      modules/islandora_text_extraction_defaults/config/optional/field.storage.media.field_edited_text.yml
  82. 0
      modules/islandora_text_extraction_defaults/config/optional/language.content_settings.media.extracted_text.yml
  83. 0
      modules/islandora_text_extraction_defaults/config/optional/media.type.extracted_text.yml
  84. 0
      modules/islandora_text_extraction_defaults/config/optional/rdf.mapping.media.extracted_text.yml
  85. 0
      modules/islandora_text_extraction_defaults/config/optional/system.action.get_ocr_from_image.yml
  86. 2
      modules/islandora_text_extraction_defaults/islandora_text_extraction_defaults.features.yml
  87. 6
      modules/islandora_video/tests/src/Functional/GenerateVideoDerivativeTest.php
  88. 2
      phpunit.xml
  89. 2
      src/Controller/ManageMembersController.php
  90. 15
      src/EventGenerator/EventGenerator.php
  91. 25
      src/Form/IslandoraSettingsForm.php
  92. 2
      src/IslandoraContextManager.php
  93. 6
      src/Plugin/Condition/NodeHasParent.php
  94. 6
      src/Plugin/Field/FieldFormatter/IslandoraImageFormatter.php
  95. 74
      src/Plugin/views/filter/NodeHasMediaUse.php
  96. 29
      src/PresetReaction/PresetReaction.php
  97. 221
      tests/modules/integer_weight_test_views/test_views/views.view.test_integer_weight.yml
  98. 8
      tests/src/Functional/AddChildTest.php
  99. 4
      tests/src/Functional/ContentEntityTypeTest.php
  100. 6
      tests/src/Functional/DerivativeReactionTest.php
  101. Some files were not shown because too many files have changed in this diff Show More

52
.github/workflows/build-2.x.yml

@ -1,34 +1,33 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the 2.x branch
push:
branches: [ 2.x ]
pull_request:
branches: [ 2.x ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
env:
DRUPAL_VERSION: ${{ matrix.drupal-version }}
SCRIPT_DIR: ${{ github.workspace }}/islandora_ci
DRUPAL_DIR: /opt/drupal
PHPUNIT_FILE: ${{ github.workspace }}/build_dir/phpunit.xml
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.allowed_failure }}
strategy:
fail-fast: false
matrix:
php-versions: ["8.1"]
# test-suite functional-javascript will appear to pass but will skip tests; missing chromedriver.
php-versions: ["8.1", "8.2", "8.3"]
test-suite: ["kernel", "functional", "functional-javascript"]
drupal-version: ["9.5.x", "10.0.x", "10.1.x"]
drupal-version: ["10.1.x", "10.2.x", "10.3.x-dev"]
mysql: ["8.0"]
allowed_failure: [false]
exclude:
- php-versions: "8.3"
drupal-version: "10.1.x"
name: PHP ${{ matrix.php-versions }} | drupal ${{ matrix.drupal-version }} | mysql ${{ matrix.mysql }} | test-suite ${{ matrix.test-suite }}
@ -48,17 +47,15 @@ jobs:
- 61616:61616
- 61613:61613
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
path: build_dir
- name: Checkout islandora_ci
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
repository: islandora/islandora_ci
ref: github-actions
@ -76,15 +73,8 @@ jobs:
sudo apt-get remove -y mysql-client mysql-common
sudo apt-get install -y mysql-client
- name: Set environment variables
run: |
echo "DRUPAL_VERSION=${{ matrix.drupal-version }}" >> $GITHUB_ENV
echo "SCRIPT_DIR=$GITHUB_WORKSPACE/islandora_ci" >> $GITHUB_ENV
echo "DRUPAL_DIR=/opt/drupal" >> $GITHUB_ENV
echo "PHPUNIT_FILE=$GITHUB_WORKSPACE/build_dir/phpunit.xml" >> $GITHUB_ENV
- name: Cache Composer dependencies
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: /tmp/composer-cache
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
@ -109,15 +99,27 @@ jobs:
run: |
cd $DRUPAL_DIR/web
drush --uri=127.0.0.1:8282 en -y islandora_audio islandora_breadcrumbs islandora_iiif islandora_image islandora_video islandora_text_extraction_defaults
drush --uri=127.0.0.1:8282 fim -y islandora_core_feature,islandora_text_extraction_defaults
- name: Copy PHPunit file
run: cp $PHPUNIT_FILE $DRUPAL_DIR/web/core/phpunit.xml
- name: Test scripts
run: $SCRIPT_DIR/travis_scripts.sh
- name: Start chromedriver
if: matrix.test-suite == 'functional-javascript'
run: |-
/usr/local/share/chromedriver-linux64/chromedriver \
--log-path=/tmp/chromedriver.log \
--verbose \
--allowed-ips= \
--allowed-origins=* &
- name: PHPUNIT tests
run: |
cd $DRUPAL_DIR/web/core
$DRUPAL_DIR/vendor/bin/phpunit --verbose --testsuite "${{ matrix.test-suite }}"
- name: Print chromedriver logs
if: matrix.test-suite == 'functional-javascript'
run: cat /tmp/chromedriver.log

5
.github/workflows/gitlab-mirror.yml

@ -3,12 +3,15 @@ name: Mirror and run GitLab CI
on:
push:
branches: [2.x]
tags: '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Mirror + trigger CI
uses: SvanBoxel/gitlab-mirror-and-ci-action@master
with:

6
composer.json

@ -17,9 +17,8 @@
"drupal/context": "^4 || ^5@RC",
"drupal/ctools": "^3.8 || ^4",
"drupal/eva" : "^3.0",
"drupal/features" : "^3.13",
"drupal/file_replace": "^1.1",
"drupal/filehash": "^2",
"drupal/filehash": "^2 || ^3",
"drupal/flysystem" : "^2.0@alpha",
"drupal/jwt": "^1.1 || ^2",
"drupal/migrate_plus" : "^5.1 || ^6",
@ -39,7 +38,8 @@
"sebastian/phpcpd": "*"
},
"suggest": {
"drupal/transliterate_filenames": "Sanitizes filenames when they are uploaded so they don't break your repository."
"drupal/transliterate_filenames": "Sanitizes filenames when they are uploaded so they don't break your repository.",
"drupal/coi": "Some configuration fields work with Config Override Inspector."
},
"license": "GPL-2.0-or-later",
"authors": [

1
config/install/islandora.settings.yml

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

6
config/schema/islandora.schema.yml

@ -17,15 +17,15 @@ islandora.settings:
delete_media_and_files:
type: boolean
label: 'Node Delete with Media and Files'
redirect_after_media_save:
type: boolean
label: 'Redirect to node after media save.'
upload_form_location:
type: string
label: 'Upload Form Location'
upload_form_allowed_mimetypes:
type: string
label: 'Upload Form Allowed Extensions'
gemini_url:
type: uri
label: 'Url to Gemini microservice'
gemini_pseudo_bundles:
type: sequence
label: 'List of node, media and taxonomy terms that should include the linked Fedora URI'

1
islandora.info.yml

@ -22,7 +22,6 @@ dependencies:
- drupal:text
- drupal:views_ui
- eva:eva
- features:features_ui
- file_replace:file_replace
- filehash:filehash
- flysystem:flysystem

14
islandora.install

@ -212,3 +212,17 @@ function islandora_update_8007() {
// have the here, just in case?
throw new UpdateException('Failed; hit the end of the update hook implementation, which is not expected.');
}
/**
* Set config to no redirect after media save.
*/
function islandora_update_8008() {
$config = \Drupal::configFactory()->getEditable('islandora.settings');
if ($config) {
$config->set('redirect_after_media_save', FALSE);
$config->save(TRUE);
return t('A new configuration option, "Redirect after media save" is now available.
It has been turned off to preserve existing behaviour. To enable this setting visit
Configuration > Islandora > Core Settings.');
}
}

24
islandora.module

@ -332,6 +332,7 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id)
if ($node) {
$form['name']['widget'][0]['value']['#default_value'] = $node->getTitle();
}
$form['actions']['submit']['#submit'][] = 'islandora_media_custom_form_submit';
}
}
@ -387,6 +388,22 @@ function islandora_form_alter(&$form, FormStateInterface $form_state, $form_id)
return $form;
}
/**
* Redirect submit handler for media save.
*/
function islandora_media_custom_form_submit(&$form, FormStateInterface $form_state) {
// Check configuration to see whether a redirect is desired.
$redirect = \Drupal::config('islandora.settings')->get('redirect_after_media_save');
if ($redirect) {
$params = \Drupal::request()->query->all();
if (!empty($params)) {
$target_id = $params['edit']['field_media_of']['widget'][0]['target_id'];
$url = Url::fromRoute('view.media_of.page_1', ['node' => $target_id]);
$form_state->setRedirectUrl($url);
}
}
}
/**
* Implements a submit handler for the delete form.
*/
@ -528,14 +545,14 @@ function islandora_object_delete_form_submit($form, FormStateInterface $form_sta
}
/**
* Implements hook_field_widget_WIDGET_TYPE_form_alter().
* Implements hook_field_widget_single_element_WIDGET_TYPE_form_alter().
*/
function islandora_field_widget_image_image_form_alter(&$element, $form_state, $context) {
function islandora_field_widget_single_element_image_image_form_alter(&$element, $form_state, $context) {
$element['#process'][] = 'islandora_add_default_image_alt_text';
}
/**
* Callback for hook_field_widget_WIDGET_TYPE_form_alter().
* Callback for hook_field_widget_single_element_WIDGET_TYPE_form_alter().
*/
function islandora_add_default_image_alt_text($element, $form_state, $form) {
if ($element['alt']['#access']) {
@ -598,6 +615,7 @@ function islandora_form_block_form_alter(&$form, FormStateInterface $form_state,
unset($form['visibility']['media_is_islandora_media']);
unset($form['visibility']['media_uses_filesystem']);
unset($form['visibility']['node_had_namespace']);
unset($form['visibility']['node_has_ancestor']);
unset($form['visibility']['node_has_parent']);
unset($form['visibility']['node_has_term']);
unset($form['visibility']['node_is_islandora_object']);

3
islandora.tokens.inc

@ -134,7 +134,7 @@ function islandora_tokens($type, $tokens, array $data, array $options, Bubbleabl
break;
case 'pdf_url':
$replacements[$original] = ' ' . islandora_url_to_service_file_media_by_mimetype($data['node'], 'application/pdf');
$replacements[$original] = islandora_url_to_service_file_media_by_mimetype($data['node'], 'application/pdf');
break;
}
}
@ -188,4 +188,5 @@ function islandora_url_to_service_file_media_by_mimetype($node, $mime_type) {
}
}
}
return '';
}

6
modules/islandora_audio/tests/src/Functional/GenerateAudioDerivativeTest.php

@ -40,7 +40,7 @@ class GenerateAudioDerivativeTest extends GenerateDerivativeTestBase {
// Create an action to generate a audio derivative.
$this->drupalGet('admin/config/system/actions');
$this->getSession()->getPage()->findById("edit-action")->selectOption("Generate a audio derivative");
$this->getSession()->getPage()->pressButton($this->t('Create'));
$this->getSession()->getPage()->pressButton('Create');
$this->assertSession()->statusCodeEquals(200);
$this->getSession()->getPage()->fillField('edit-label', "Generate audio test derivative");
@ -53,7 +53,7 @@ class GenerateAudioDerivativeTest extends GenerateDerivativeTestBase {
$this->getSession()->getPage()->fillField('edit-args', "-f mp3");
$this->getSession()->getPage()->fillField('edit-scheme', "public");
$this->getSession()->getPage()->fillField('edit-path', "derp.mov");
$this->getSession()->getPage()->pressButton($this->t('Save'));
$this->getSession()->getPage()->pressButton('Save');
$this->assertSession()->statusCodeEquals(200);
// Create a context and add the action as a derivative reaction.
@ -69,7 +69,7 @@ class GenerateAudioDerivativeTest extends GenerateDerivativeTestBase {
'field_media_use[0][target_id]' => $this->preservationMasterTerm->label(),
];
$this->drupalGet('media/add/' . $this->testMediaType->id());
$this->submitForm($values, $this->t('Save'));
$this->submitForm($values, 'Save');
$expected = [
'source_uri' => 'test_file.txt',

100
modules/islandora_core_feature/config/install/features.bundle.islandora.yml

@ -1,100 +0,0 @@
langcode: en
status: true
dependencies:
enforced:
module:
- islandora_core_feature
name: Islandora
machine_name: islandora
description: 'Features for islandora'
assignments:
alter:
core: true
uuid: true
user_permissions: true
enabled: true
weight: 0
base:
types:
config:
comment_type: comment_type
node_type: node_type
content:
user: user
enabled: true
weight: -2
core:
types:
config:
date_format: date_format
field_storage_config: field_storage_config
entity_form_mode: entity_form_mode
image_style: image_style
menu: menu
responsive_image_style: responsive_image_style
user_role: user_role
entity_view_mode: entity_view_mode
enabled: true
weight: 5
dependency:
enabled: true
weight: 15
exclude:
types:
config:
features_bundle: features_bundle
curated: true
module:
installed: true
profile: true
namespace: true
namespace_any: false
enabled: true
weight: -5
existing:
enabled: true
weight: 12
forward_dependency:
enabled: true
weight: 4
namespace:
enabled: true
weight: 0
optional:
types:
config: { }
enabled: true
weight: 0
packages:
enabled: true
weight: -20
profile:
curated: true
standard:
files: true
dependencies: true
types:
config:
block: block
language_content_settings: language_content_settings
configurable_language: configurable_language
migration: migration
shortcut_set: shortcut_set
tour: tour
enabled: true
weight: 10
site:
types:
config:
action: action
contact_form: contact_form
block_content_type: block_content_type
rdf_mapping: rdf_mapping
search_page: search_page
taxonomy_vocabulary: taxonomy_vocabulary
editor: editor
filter_format: filter_format
enabled: true
weight: 7
profile_name: ''
is_profile: false

0
modules/islandora_core_feature/config/install/core.entity_view_mode.media.source.yml → modules/islandora_core_feature/config/optional/core.entity_view_mode.media.source.yml

0
modules/islandora_core_feature/config/install/field.field.taxonomy_term.islandora_media_use.field_external_uri.yml → modules/islandora_core_feature/config/optional/field.field.taxonomy_term.islandora_media_use.field_external_uri.yml

0
modules/islandora_core_feature/config/install/field.field.taxonomy_term.islandora_models.field_external_uri.yml → modules/islandora_core_feature/config/optional/field.field.taxonomy_term.islandora_models.field_external_uri.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_file_size.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_file_size.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_height.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_height.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_audio_file.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_audio_file.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_document.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_document.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_file.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_file.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_image.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_image.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_of.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_of.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_use.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_use.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_media_video_file.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_media_video_file.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_mime_type.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_mime_type.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_original_name.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_original_name.yml

0
modules/islandora_core_feature/config/install/field.storage.media.field_width.yml → modules/islandora_core_feature/config/optional/field.storage.media.field_width.yml

0
modules/islandora_core_feature/config/install/field.storage.node.field_member_of.yml → modules/islandora_core_feature/config/optional/field.storage.node.field_member_of.yml

0
modules/islandora_core_feature/config/install/field.storage.node.field_model.yml → modules/islandora_core_feature/config/optional/field.storage.node.field_model.yml

0
modules/islandora_core_feature/config/install/field.storage.node.field_weight.yml → modules/islandora_core_feature/config/optional/field.storage.node.field_weight.yml

0
modules/islandora_core_feature/config/install/field.storage.taxonomy_term.field_external_uri.yml → modules/islandora_core_feature/config/optional/field.storage.taxonomy_term.field_external_uri.yml

0
modules/islandora_core_feature/config/install/filehash.settings.yml → modules/islandora_core_feature/config/optional/filehash.settings.yml

0
modules/islandora_core_feature/config/install/migrate_plus.migration.islandora_tags.yml → modules/islandora_core_feature/config/optional/migrate_plus.migration.islandora_tags.yml

0
modules/islandora_core_feature/config/install/migrate_plus.migration_group.islandora.yml → modules/islandora_core_feature/config/optional/migrate_plus.migration_group.islandora.yml

0
modules/islandora_core_feature/config/install/rest.resource.entity.file.yml → modules/islandora_core_feature/config/optional/rest.resource.entity.file.yml

0
modules/islandora_core_feature/config/install/rest.resource.entity.media.yml → modules/islandora_core_feature/config/optional/rest.resource.entity.media.yml

0
modules/islandora_core_feature/config/install/rest.resource.entity.node.yml → modules/islandora_core_feature/config/optional/rest.resource.entity.node.yml

0
modules/islandora_core_feature/config/install/rest.resource.entity.taxonomy_term.yml → modules/islandora_core_feature/config/optional/rest.resource.entity.taxonomy_term.yml

0
modules/islandora_core_feature/config/install/system.action.delete_file_as_fedora_external_content.yml → modules/islandora_core_feature/config/optional/system.action.delete_file_as_fedora_external_content.yml

0
modules/islandora_core_feature/config/install/system.action.delete_media_from_triplestore.yml → modules/islandora_core_feature/config/optional/system.action.delete_media_from_triplestore.yml

0
modules/islandora_core_feature/config/install/system.action.delete_node_from_fedora.yml → modules/islandora_core_feature/config/optional/system.action.delete_node_from_fedora.yml

0
modules/islandora_core_feature/config/install/system.action.delete_node_from_triplestore.yml → modules/islandora_core_feature/config/optional/system.action.delete_node_from_triplestore.yml

0
modules/islandora_core_feature/config/install/system.action.delete_taxonomy_term_in_fedora.yml → modules/islandora_core_feature/config/optional/system.action.delete_taxonomy_term_in_fedora.yml

0
modules/islandora_core_feature/config/install/system.action.delete_taxonomy_term_in_triplestore.yml → modules/islandora_core_feature/config/optional/system.action.delete_taxonomy_term_in_triplestore.yml

0
modules/islandora_core_feature/config/install/system.action.index_file_as_fedora_external_content.yml → modules/islandora_core_feature/config/optional/system.action.index_file_as_fedora_external_content.yml

0
modules/islandora_core_feature/config/install/system.action.index_media_in_fedora.yml → modules/islandora_core_feature/config/optional/system.action.index_media_in_fedora.yml

0
modules/islandora_core_feature/config/install/system.action.index_media_in_triplestore.yml → modules/islandora_core_feature/config/optional/system.action.index_media_in_triplestore.yml

0
modules/islandora_core_feature/config/install/system.action.index_node_in_fedora.yml → modules/islandora_core_feature/config/optional/system.action.index_node_in_fedora.yml

0
modules/islandora_core_feature/config/install/system.action.index_node_in_triplestore.yml → modules/islandora_core_feature/config/optional/system.action.index_node_in_triplestore.yml

0
modules/islandora_core_feature/config/install/system.action.index_taxonomy_term_in_fedora.yml → modules/islandora_core_feature/config/optional/system.action.index_taxonomy_term_in_fedora.yml

0
modules/islandora_core_feature/config/install/system.action.index_taxonomy_term_in_the_triplestore.yml → modules/islandora_core_feature/config/optional/system.action.index_taxonomy_term_in_the_triplestore.yml

0
modules/islandora_core_feature/config/install/taxonomy.vocabulary.islandora_media_use.yml → modules/islandora_core_feature/config/optional/taxonomy.vocabulary.islandora_media_use.yml

0
modules/islandora_core_feature/config/install/taxonomy.vocabulary.islandora_models.yml → modules/islandora_core_feature/config/optional/taxonomy.vocabulary.islandora_models.yml

0
modules/islandora_core_feature/config/install/views.view.all_taxonomy_terms.yml → modules/islandora_core_feature/config/optional/views.view.all_taxonomy_terms.yml

0
modules/islandora_core_feature/config/install/views.view.display_media.yml → modules/islandora_core_feature/config/optional/views.view.display_media.yml

0
modules/islandora_core_feature/config/install/views.view.file_checksum.yml → modules/islandora_core_feature/config/optional/views.view.file_checksum.yml

0
modules/islandora_core_feature/config/install/views.view.manage_members.yml → modules/islandora_core_feature/config/optional/views.view.manage_members.yml

0
modules/islandora_core_feature/config/install/views.view.media_of.yml → modules/islandora_core_feature/config/optional/views.view.media_of.yml

0
modules/islandora_core_feature/config/install/views.view.non_fedora_files.yml → modules/islandora_core_feature/config/optional/views.view.non_fedora_files.yml

0
modules/islandora_core_feature/config/install/views.view.reorder_children.yml → modules/islandora_core_feature/config/optional/views.view.reorder_children.yml

16
modules/islandora_core_feature/islandora_core_feature.features.yml

@ -1,16 +0,0 @@
bundle: islandora
excluded:
- language.content_settings.taxonomy_term.islandora_media_use
- language.content_settings.taxonomy_term.islandora_models
required:
- features.bundle.islandora
- field.storage.media.field_file_size
- field.storage.media.field_height
- field.storage.media.field_media_of
- field.storage.media.field_media_use
- field.storage.media.field_mime_type
- field.storage.media.field_width
- field.storage.node.field_member_of
- field.storage.node.field_model
- field.storage.node.field_weight
- field.storage.taxonomy_term.field_external_uri

1
modules/islandora_core_feature/islandora_core_feature.info.yml

@ -6,7 +6,6 @@ dependencies:
- drupal:basic_auth
- drupal:content_translation
- drupal:eva
- drupal:features
- drupal:field
- drupal:file
- drupal:filehash

15
modules/islandora_iiif/README.md

@ -38,21 +38,6 @@ This module implements a Views Style plugin. It provides the following settings:
1. Tile Source: A field that was added to the views list of fields with the image to be served. This should be a File or Image type field on a Media.
2. Structured Text field: This lets you specify a file field where OCR text with positional data, e.g., hOCR can be found.
### Media Attributes from IIIF Action
The module also provides an action that lets a site owner populate a TIFF or JP2 image's width and
height attributes into fields so the IIIF server is not bogged down trying to generate a manifest if
it doesn't have them.
To use it, either:
- Add it as a derivative reaction to a node with an Original FIle as its child, or
- Use it as a batch action, such as on a Paged Content object's list of child pages.
The action assumes the media type has fields with machine names of field_height and
field_width. Making this configurable would mean they would not appear
on entity list pages.
## Documentation
Official documentation is available on the [Islandora 8 documentation site](https://islandora.github.io/documentation/).

10
modules/islandora_iiif/config/optional/system.action.media_attributes_from_iiif_action.yml

@ -1,10 +0,0 @@
langcode: en
status: true
dependencies:
module:
- islandora_iiif
id: media_attributes_from_iiif_action
label: 'Media attributes from IIIF'
type: node
plugin: islandora_iiif:media_attributes_from_iiif_action:media
configuration: { }

18
modules/islandora_iiif/config/schema/islandora_iiif.schema.yml

@ -6,28 +6,28 @@ islandora_iiif.settings:
type: string
label: 'IIIF Server Url'
use_relative_paths:
type: boolean
label: 'Use relative paths in manifest.'
type: boolean
label: 'Use relative paths in manifest.'
show_title:
type: string
label: 'Show title in view'
views.style.iiif_manifest:
type: views_style
mapping:
iiif_tile_field:
type: sequence
label: "Tile source field(s)"
sequence:
type: string
label: "Tile source field(s)"
iiif_ocr_file_field:
type: sequence
label: "Structured OCR data file field"
sequence:
type: string:
label: "IIIF hOCR file field"
structured_text_term:
type: string
structured_text_term_uri:
type: string
label: "Structured text term"
getdimensions_from_sewrver:
type: boolean
label: "Retrieve image dimensions from IIIF server"
search_endpoint:
type: string
label: "Search endpoint path"

18
modules/islandora_iiif/islandora_iiif.install

@ -1,18 +0,0 @@
<?php
/**
* @file
* Install/update hook implementations.
*/
use Symfony\Component\Yaml\Yaml;
/**
* Add Media Attributes from IIIF action.
*/
function islandora_iiif_update_92001(&$sandbox) {
$config_id = 'system.action.media_attributes_from_iiif_action';
$config_path = \Drupal::service('extension.list.module')->getPath('islandora_iiif') . '/config/optional/' . $config_id . '.yml';
$data = Yaml::parseFile($config_path);
\Drupal::configFactory()->getEditable($config_id)->setData($data)->save(TRUE);
}

4
modules/islandora_iiif/islandora_iiif.services.yml

@ -1,4 +0,0 @@
services:
islandora_iiif:
class: Drupal\islandora_iiif\IiifInfo
arguments: ['@config.factory', '@http_client', '@logger.channel.islandora', '@jwt.authentication.jwt']

17
modules/islandora_iiif/src/Form/IslandoraIIIFConfigForm.php

@ -66,12 +66,20 @@ class IslandoraIIIFConfigForm extends ConfigFormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$options = [
'none' => $this->t('None'),
'view' => $this->t("From view title"),
'node' => $this->t("From node title"),
];
$config = $this->config('islandora_iiif.settings');
$form['iiif_server'] = [
'#type' => 'url',
'#title' => $this->t('IIIF Image server location'),
'#description' => $this->t('Please enter the image server location without trailing slash. e.g. http://www.example.org/iiif/2.'),
'#default_value' => $config->get('iiif_server'),
'#config' => [
'key' => 'islandora_iiif.settings:iiif_server',
],
];
$form['use_relative_paths'] = [
@ -81,6 +89,14 @@ class IslandoraIIIFConfigForm extends ConfigFormBase {
'#default_value' => $config->get('use_relative_paths'),
];
$form['show_title'] = [
'#type' => 'select',
'#options' => $options,
'#title' => $this->t("Show title in viewer."),
'#description' => $this->t("Show title on your viewer, if viewer allows"),
'#default_value' => $config->get('show_title'),
];
return parent::buildForm($form, $form_state);
}
@ -108,6 +124,7 @@ class IslandoraIIIFConfigForm extends ConfigFormBase {
$this->config('islandora_iiif.settings')
->set('iiif_server', $form_state->getValue('iiif_server'))
->set('use_relative_paths', $form_state->getValue('use_relative_paths'))
->set('show_title', $form_state->getValue('show_title'))
->save();
}

153
modules/islandora_iiif/src/IiifInfo.php

@ -1,153 +0,0 @@
<?php
namespace Drupal\islandora_iiif;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\file\FileInterface;
use Drupal\jwt\Authentication\Provider\JwtAuth;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ServerException;
/**
* Get IIIF related info for a given File or Image entity.
*/
class IiifInfo {
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The HTTP client.
*
* @var \GuzzleHttp\Client
*/
protected $httpClient;
/**
* This module's config.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $iiifConfig;
/**
* JWT Auth provider service.
*
* @var \Drupal\jwt\Authentication\Provider\JwtAuth
*/
protected $jwtAuth;
/**
* The logger.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* Constructs an IiifInfo object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Guzzle\Http\Client $http_client
* The HTTP Client.
* @param \Drupal\Core\Logger\LoggerChannelInterface $channel
* Logger channel.
* @param \Drupal\jwt\Authentication\Provider\JwtAuth $jwt_auth
* The JWT auth provider.
*/
public function __construct(ConfigFactoryInterface $config_factory, Client $http_client, LoggerChannelInterface $channel, JwtAuth $jwt_auth) {
$this->configFactory = $config_factory;
$this->iiifConfig = $this->configFactory->get('islandora_iiif.settings');
$this->httpClient = $http_client;
$this->logger = $channel;
$this->jwtAuth = $jwt_auth;
}
/**
* The IIIF base URL for an image.
*
* Visiting this URL will resolve to the info.json for the image.
*
* @return string
* The absolute URL on the IIIF server.
*/
public function baseUrl($image) {
if ($this->iiifConfig->get('use_relative_paths')) {
$file_url = ltrim($image->createFileUrl(TRUE), '/');
}
else {
$file_url = $image->createFileUrl(FALSE);
}
$iiif_address = $this->iiifConfig->get('iiif_server');
$iiif_url = rtrim($iiif_address, '/') . '/' . urlencode($file_url);
return $iiif_url;
}
/**
* Retrieve an image's original dimensions via the IIIF server.
*
* @param \Drupal\File\FileInterface $file
* The image file.
*
* @return array|false
* The image dimensions in an array as [$width, $height]
*/
public function getImageDimensions(FileInterface $file) {
$iiif_url = $this->baseUrl($file);
try {
$info_json = $this->httpClient->request('get', $iiif_url, [
'headers' => [
'Authorization' => 'Bearer ' . $this->jwtAuth->generateToken(),
],
])->getBody();
$resource = json_decode($info_json, TRUE);
$width = $resource['width'];
$height = $resource['height'];
if (is_numeric($width) && is_numeric($height)) {
return [intval($width), intval($height)];
}
}
catch (ClientException | ConnectException | ServerException $e) {
$this->logger->info("Error getting image file dimensions from IIIF server: " . $e->getMessage());
}
return FALSE;
}
/**
* The IIIF base URL for an image.
*
* Visiting this URL will resolve to the full image resized to the maximum dimensions given.
*
* @see https://iiif.io/api/image/2.1/
*
* @param Drupal\file\FileInterface $image
* The image entity.
* @param int width
* The maximum width of the image to be returned. 0 for no constraint.
* @param int $height
* The maxim um height of the image to be returned. 0 for no contraint.
*
* @return string
* The IIIF URl to retrieve the full image with the given max dimensions.
*/
public function getImageWithMaxDimensions($image, $width = 0, $height = 0) {
$base_url = $this->baseUrl($image);
return $base_url . "/full/!$width,$height/0/default.jpg";
}
}

165
modules/islandora_iiif/src/Plugin/Action/MediaAttributesFromIiif.php

@ -1,165 +0,0 @@
<?php
namespace Drupal\islandora_iiif\Plugin\Action;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Action\Plugin\Action\SaveAction;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\islandora\IslandoraUtils;
use Drupal\islandora\MediaSource\MediaSourceService;
use Drupal\islandora_iiif\IiifInfo;
use GuzzleHttp\Client;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides an action that can save any entity.
*
* @Action(
* id = "islandora_iiif:media_attributes_from_iiif_action",
* action_label = @Translation("Add image dimensions retrieved from the IIIF server"),
* deriver = "Drupal\Core\Action\Plugin\Action\Derivative\EntityChangedActionDeriver",
* )
*/
class MediaAttributesFromIiif extends SaveAction {
/**
* The HTTP client.
*
* @var \GuzzleHttp\Client
*/
protected $httpClient;
/**
* The IIIF Info service.
*
* @var \Drupal\islandora_iiif\IiifInfo
*/
protected $iiifInfo;
/**
* The logger.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* Islandora utility functions.
*
* @var \Drupal\islandora\IslandoraUtils
*/
protected $utils;
/**
* A MediaSourceService.
*
* @var \Drupal\islandora\MediaSource\MediaSourceService
*/
protected $mediaSource;
/**
* Constructs a TiffMediaSaveAction object.
*
* @param mixed[] $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\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
* @param \Guzzle\Http\Client $http_client
* The HTTP Client.
* @param \Drupal\islandora_iiif\IiifInfo $iiif_info
* The IIIF INfo service.
* @param \Drupal\islandora\IslandoraUtils $islandora_utils
* Islandora utility functions.
* @param \Drupal\islandora\MediaSource\MediaSourceService $media_source
* Islandora media service.
* @param \Drupal\Core\Logger\LoggerChannelInterface $channel
* Logger channel.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, TimeInterface $time, Client $http_client, IiifInfo $iiif_info, IslandoraUtils $islandora_utils, MediaSourceService $media_source, LoggerChannelInterface $channel) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $time);
$this->httpClient = $http_client;
$this->iiifInfo = $iiif_info;
$this->utils = $islandora_utils;
$this->mediaSource = $media_source;
$this->logger = $channel;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('datetime.time'),
$container->get('http_client'),
$container->get('islandora_iiif'),
$container->get('islandora.utils'),
$container->get('islandora.media_source_service'),
$container->get('logger.channel.islandora')
);
}
/**
* {@inheritdoc}
*/
public function execute($entity = NULL) {
$width = $height = FALSE;
// Get the original File media use term.
$original_file_term = $this->utils->getTermForUri('http://pcdm.org/use#OriginalFile');
/**
* @var \Drupal\media\MediaInterface $original_file_media
*/
$original_file_mids = $this->utils->getMediaReferencingNodeAndTerm($entity, $original_file_term);
if (!empty($original_file_mids)) {
// Ordinarily there shouldn't be more than one Original File media but
// it's not guaranteed.
foreach ($original_file_mids as $original_file_mid) {
/**
* @var \Drupal\Media\MediaInterface $original_file_media
*/
$original_file_media = $this->entityTypeManager->getStorage('media')->load($original_file_mid);
// Get the media MIME Type.
$original_file = $this->mediaSource->getSourceFile($original_file_media);
$mime_type = $original_file->getMimeType();
if (in_array($mime_type, ['image/tiff', 'image/jp2'])) {
[$width, $height] = $this->iiifInfo->getImageDimensions($original_file);
}
// @todo Make field configurable. Low priority since this whole thing is a workaround for an Islandora limitation.
if ($original_file_media->hasField('field_width') && $original_file_media->hasField('field_height')) {
$original_file_media->set('field_height', $height);
$original_file_media->set('field_width', $width);
$original_file_media->save();
}
}
}
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
/** @var \Drupal\Core\Entity\EntityInterface $object */
return $object->access('update', $account, $return_as_object);
}
}

248
modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php

@ -6,20 +6,22 @@ use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\media\Entity\Media;
use Drupal\islandora\IslandoraUtils;
use Drupal\islandora_iiif\IiifInfo;
use Drupal\taxonomy\TermInterface;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\views\ResultRow;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ServerException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Provide serializer format for IIIF Manifest.
@ -42,7 +44,6 @@ class IIIFManifest extends StylePluginBase {
*/
protected $utils;
/**
* {@inheritdoc}
*/
@ -67,13 +68,6 @@ class IIIFManifest extends StylePluginBase {
*/
protected $serializer;
/**
* The IIIF Info service.
*
* @var \Drupal\islandora_iiif\IiifInfo
*/
protected $iiifInfo;
/**
* The request service.
*
@ -102,6 +96,13 @@ class IIIFManifest extends StylePluginBase {
*/
protected $fileSystem;
/**
* The Guzzle HTTP Client.
*
* @var \GuzzleHttp\Client
*/
protected $httpClient;
/**
* The messenger.
*
@ -116,10 +117,24 @@ class IIIFManifest extends StylePluginBase {
*/
protected $moduleHandler;
/**
* Memoized structured text term.
*
* @var \Drupal\taxonomy\TermInterface|null
*/
protected ?TermInterface $structuredTextTerm;
/**
* Flag to track if we _have_ attempted a lookup, as the value is nullable.
*
* @var bool
*/
protected bool $structuredTextTermMemoized = FALSE;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, SerializerInterface $serializer, Request $request, ImmutableConfig $iiif_config, EntityTypeManagerInterface $entity_type_manager, FileSystemInterface $file_system, Client $http_client, MessengerInterface $messenger, ModuleHandlerInterface $moduleHandler, IslandoraUtils $utils, IiifInfo $iiif_info) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, SerializerInterface $serializer, Request $request, ImmutableConfig $iiif_config, EntityTypeManagerInterface $entity_type_manager, FileSystemInterface $file_system, Client $http_client, MessengerInterface $messenger, ModuleHandlerInterface $moduleHandler, IslandoraUtils $utils) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->serializer = $serializer;
@ -129,9 +144,8 @@ class IIIFManifest extends StylePluginBase {
$this->fileSystem = $file_system;
$this->httpClient = $http_client;
$this->messenger = $messenger;
$this->moduleHandler = $moduleHandler;
$this->utils = $utils;
$this->iiifInfo = $iiif_info;
$this->moduleHandler = $moduleHandler;
}
/**
@ -150,8 +164,7 @@ class IIIFManifest extends StylePluginBase {
$container->get('http_client'),
$container->get('messenger'),
$container->get('module_handler'),
$container->get('islandora.utils'),
$container->get('islandora_iiif')
$container->get('islandora.utils')
);
}
@ -179,20 +192,33 @@ class IIIFManifest extends StylePluginBase {
// @todo assumming the view is a path like /node/1/manifest.json
$url_components = explode('/', trim($request_url, '/'));
array_pop($url_components);
$content_path = implode('/', $url_components);
$iiif_base_id = $request_host . '/' . $content_path;
$content_path = '/' . implode('/', $url_components);
$iiif_base_id = "{$request_host}{$content_path}";
$display = $this->iiifConfig->get('show_title');
switch ($display) {
case 'none':
$label = '';
break;
case 'view':
$label = $this->view->getTitle();
break;
case 'node':
$label = $this->getEntityTitle($content_path);
/**
* @var \Drupal\taxonomy\TermInterface|null
*/
$structured_text_term = $this->utils->getTermForUri($this->options['structured_text_term_uri']);
break;
default:
$label = $this->t("IIIF Manifest");
}
// @see https://iiif.io/api/presentation/2.1/#manifest
$json += [
'@type' => 'sc:Manifest',
'@id' => $request_url,
// If the View has a title, set the View title as the manifest label.
'label' => $this->view->getTitle() ?: $this->getEntityTitle($content_path),
'label' => $label,
'@context' => 'http://iiif.io/api/presentation/2/context.json',
// @see https://iiif.io/api/presentation/2.1/#sequence
'sequences' => [
@ -206,7 +232,7 @@ class IIIFManifest extends StylePluginBase {
// For each row in the View result.
foreach ($this->view->result as $row) {
// Add the IIIF URL to the image to print out as JSON.
$canvases = $this->getTileSourceFromRow($row, $iiif_address, $iiif_base_id, $structured_text_term);
$canvases = $this->getTileSourceFromRow($row, $iiif_address, $iiif_base_id);
foreach ($canvases as $tile_source) {
$json['sequences'][0]['canvases'][] = $tile_source;
}
@ -216,8 +242,8 @@ class IIIFManifest extends StylePluginBase {
$content_type = 'json';
// Add a search endpoint if one is defined
$this->addSearchEndpoint($json, $url_components);
// Add a search endpoint if one is defined.
$this->addSearchEndpoint($json, $url_components);
// Give other modules a chance to alter the manifest.
$this->moduleHandler->alter('islandora_iiif_manifest', $json, $this);
@ -235,13 +261,11 @@ $this->addSearchEndpoint($json, $url_components);
* @param string $iiif_base_id
* The URL for the request, minus the last part of the URL,
* which is likely "manifest".
* @param \Drupal\taxonomy\TermInterface|null $structured_text_term
* The term that structured text media references, if any.
*
* @return array
* List of IIIF URLs to display in the Openseadragon viewer.
*/
protected function getTileSourceFromRow(ResultRow $row, $iiif_address, $iiif_base_id, $structured_text_term) {
protected function getTileSourceFromRow(ResultRow $row, $iiif_address, $iiif_base_id) {
$canvases = [];
foreach (array_filter(array_values($this->options['iiif_tile_field'])) as $iiif_tile_field) {
$viewsField = $this->view->field[$iiif_tile_field];
@ -272,10 +296,7 @@ $this->addSearchEndpoint($json, $url_components);
$canvas_id = $iiif_base_id . '/canvas/' . $entity->id();
$annotation_id = $iiif_base_id . '/annotation/' . $entity->id();
[$width, $height] = $this->getCanvasDimensions($iiif_url, $entity, $image, $mime_type);
if ($width == 0) {
continue;
}
[$width, $height] = $this->getCanvasDimensions($iiif_url, $image, $mime_type);
$tmp_canvas = [
// @see https://iiif.io/api/presentation/2.1/#canvas
@ -307,7 +328,7 @@ $this->addSearchEndpoint($json, $url_components);
],
];
if ($ocr_url = $this->getOcrUrl($entity, $structured_text_term)) {
if ($ocr_url = $this->getOcrUrl($entity)) {
$tmp_canvas['seeAlso'] = [
'@id' => $ocr_url,
'format' => 'text/vnd.hocr+html',
@ -344,70 +365,42 @@ $this->addSearchEndpoint($json, $url_components);
* @return [string]
* The width and height of the image.
*/
protected function getCanvasDimensions(string $iiif_url, Media $media, FieldItemInterface $image, string $mime_type) {
// If the media has field_height and field_width, return those values.
if ($media->hasField('field_height')
&& !$media->get('field_height')->isEmpty()
&& $media->get('field_height')->value > 0
&& $media->hasField('field_width')
&& !$media->get('field_width')->isEmpty()
&& $media->get('field_width')->value > 0) {
return [intval($media->get('field_width')->value),
intval($media->get('field_height')->value),
];
}
protected function getCanvasDimensions(string $iiif_url, FieldItemInterface $image, string $mime_type) {
// Otherwise start looking at the field/file level for the numbers.
if (isset($image->width) && is_numeric($image->width)
&& isset($image->height) && is_numeric($image->height)) {
return [intval($image->width),
intval($image->height),
];
}
if ($properties = $image->getProperties()
&& isset($properties['width']) && is_numeric($properties['width'])
&& isset($properties['height']) && is_numeric($properties['width'])) {
return [intval($properties['width']),
intval($properties['height']),
];
return [intval($image->width), intval($image->height)];
}
$entity = $image->entity;
if ($entity->hasField('field_height') && !$entity->get('field_height')->isEmpty()
&& $entity->get('field_height')->value > 0
&& $entity->hasField('field_width')
&& !$entity->get('field_width')->isEmpty()
&& $entity->get('field_width')->value > 0) {
return [$entity->get('field_width')->value,
$entity->get('field_height')->value,
];
try {
$info_json = $this->httpClient->get($iiif_url)->getBody();
$resource = json_decode($info_json, TRUE);
$width = $resource['width'];
$height = $resource['height'];
}
if ($mime_type === 'image/tiff') {
// If this is a TIFF AND we don't know the width/height
// see if we can get the image size via PHP's core function.
$uri = $image->entity->getFileUri();
$path = $this->fileSystem->realpath($uri);
if (!empty($path)) {
$image_size = getimagesize($path);
if ($image_size) {
return [intval($image_size[0]),
intval($image_size[1]),
];
catch (ClientException | ServerException | ConnectException $e) {
// If we couldn't get the info.json from IIIF
// try seeing if we can get it from Drupal.
if (empty($width) || empty($height)) {
// Get the image properties so we know the image width/height.
$properties = $image->getProperties();
$width = isset($properties['width']) ? $properties['width'] : 0;
$height = isset($properties['height']) ? $properties['height'] : 0;
// If this is a TIFF AND we don't know the width/height
// see if we can get the image size via PHP's core function.
if ($mime_type === 'image/tiff' && (!$width || !$height)) {
$uri = $image->entity->getFileUri();
$path = $this->fileSystem->realpath($uri);
$image_size = getimagesize($path);
if ($image_size) {
$width = $image_size[0];
$height = $image_size[1];
}
}
}
}
// As a last resort, get it from the IIIF server.
// This can be very slow and will fail if there are too many pages.
$dimensions = $this->iiifInfo->getImageDimensions($image->entity);
if ($dimensions !== FALSE) {
return $dimensions;
}
return [0, 0];
return [$width, $height];
}
/**
@ -415,14 +408,12 @@ $this->addSearchEndpoint($json, $url_components);
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity at the current row.
* @param \Drupal\taxonomy\TermInterface|null $structured_text_term
* The term that structured text media references, if any.
*
* return String|FALSE
* @return string|false
* The absolute URL of the current row's structured text,
* or FALSE if none.
*/
protected function getOcrUrl(EntityInterface $entity, $structured_text_term) {
protected function getOcrUrl(EntityInterface $entity) {
$ocr_url = FALSE;
$iiif_ocr_file_field = !empty($this->options['iiif_ocr_file_field']) ? array_filter(array_values($this->options['iiif_ocr_file_field'])) : [];
$ocrField = count($iiif_ocr_file_field) > 0 ? $this->view->field[$iiif_ocr_file_field[0]] : NULL;
@ -432,10 +423,12 @@ $this->addSearchEndpoint($json, $url_components);
if (!is_null($ocr_field_name)) {
$ocrs = $ocr_entity->{$ocr_field_name};
$ocr = $ocrs[0] ?? FALSE;
$ocr_url = $ocr->entity->createFileUrl(FALSE);
if ($ocr) {
$ocr_url = $ocr->entity->createFileUrl(FALSE);
}
}
}
elseif ($structured_text_term) {
elseif ($structured_text_term = $this->getStructuredTextTerm()) {
$parent_node = $this->utils->getParentNode($entity);
$ocr_entity_array = $this->utils->getMediaReferencingNodeAndTerm($parent_node, $structured_text_term);
$ocr_entity_id = is_array($ocr_entity_array) ? array_shift($ocr_entity_array) : NULL;
@ -479,23 +472,6 @@ $this->addSearchEndpoint($json, $url_components);
return $entity_title;
}
protected function addSearchEndpoint(array &$json, array $url_components) {
$url_base = $this->getRequest()->getSchemeAndHttpHost();
$hocr_search_path = $this->options['search_endpoint'];
$hocr_search_url = $url_base . '/' . ltrim($hocr_search_path, '/');
$hocr_search_url = str_replace('%node', $url_components[1], $hocr_search_url);
$json['service'][] = [
"@context" => "http://iiif.io/api/search/0/context.json",
"@id" => $hocr_search_url,
"profile" => "http://iiif.io/api/search/0/search",
"label" => t("Search inside this work"),
];
}
/**
* {@inheritdoc}
*/
@ -508,6 +484,29 @@ $this->addSearchEndpoint($json, $url_components);
return $options;
}
/**
* Add the configured search endpoint to the manifest.
*
* @param array $json
* The IIIF manifest.
* @param array $url_components
* The search endpoint URL as array.
*/
protected function addSearchEndpoint(array &$json, array $url_components) {
$url_base = $this->getRequest()->getSchemeAndHttpHost();
$hocr_search_path = $this->options['search_endpoint'];
$hocr_search_url = $url_base . '/' . ltrim($hocr_search_path, '/');
$hocr_search_url = str_replace('%node', $url_components[1], $hocr_search_url);
$json['service'][] = [
"@context" => "http://iiif.io/api/search/0/context.json",
"@id" => $hocr_search_url,
"profile" => "http://iiif.io/api/search/0/search",
"label" => t("Search inside this work"),
];
}
/**
* {@inheritdoc}
*/
@ -564,15 +563,16 @@ $this->addSearchEndpoint($json, $url_components);
'#title' => $this->t('Structured OCR data file field'),
'#type' => 'checkboxes',
'#default_value' => $this->options['iiif_ocr_file_field'],
'#description' => $this->t('The source of structured OCR text for each entity. If the term setting below is left blank, it will be the same entity as the source image'),
'#description' => $this->t("If the hOCR is a field on the same entity as the image source field above, select it here. If it's found in a related entity via the term below, leave this blank."),
'#options' => $field_options,
'#required' => FALSE,
];
$form['structured_text_term'] = [
'#type' => 'entity_autocomplete',
'#target_type' => 'taxonomy_term',
'#title' => $this->t('Structured OCR text term'),
'#default_value' => $this->utils->getTermForUri($this->options['structured_text_term_uri']),
'#default_value' => $this->getStructuredTextTerm(),
'#required' => FALSE,
'#description' => $this->t('Term indicating the media that holds structured text, such as hOCR, for the given object. Use this if the text is on a separate media from the tile source.'),
];
@ -580,7 +580,7 @@ $this->addSearchEndpoint($json, $url_components);
$form['search_endpoint'] = [
'#type' => 'textfield',
'#title' => $this->t("Search endpoint path."),
'#description' => $this->t("If there is a search endpoint to search within the book that returns IIIF annotations, put it here. Use substitutions %node and %keywords.<br>E.g., paged-content-search/%node?search-in-pages=%keywords"),
'#description' => $this->t("If there is a search endpoint to search within the book that returns IIIF annotations, put it here. Use %node substitution where needed.<br>E.g., paged-content-search/%node"),
'#default_value' => $this->options['search_endpoint'],
'#required' => FALSE,
];
@ -611,10 +611,26 @@ $this->addSearchEndpoint($json, $url_components);
// @codingStandardsIgnoreEnd
$style_options = $form_state->getValue('style_options');
$tid = $style_options['structured_text_term'];
unset($style_options['structured_text_term']);
$term = $this->entityTypeManager->getStorage('taxonomy_term')->load($tid);
$style_options['structured_text_term_uri'] = $this->utils->getUriForTerm($term);
$form_state->setValue('style_options', $style_options);
parent::submitOptionsForm($form, $form_state);
}
/**
* Get the structured text term.
*
* @return \Drupal\taxonomy\TermInterface|null
* The term if it could be found; otherwise, NULL.
*/
protected function getStructuredTextTerm() : ?TermInterface {
if (!$this->structuredTextTermMemoized) {
$this->structuredTextTermMemoized = TRUE;
$this->structuredTextTerm = $this->utils->getTermForUri($this->options['structured_text_term_uri']);
}
return $this->structuredTextTerm;
}
}

6
modules/islandora_image/tests/src/Functional/GenerateImageDerivativeTest.php

@ -42,7 +42,7 @@ class GenerateImageDerivativeTest extends GenerateDerivativeTestBase {
// Create an action to generate a jpeg thumbnail.
$this->drupalGet('admin/config/system/actions');
$this->getSession()->getPage()->findById("edit-action")->selectOption("Generate an image derivative");
$this->getSession()->getPage()->pressButton($this->t('Create'));
$this->getSession()->getPage()->pressButton('Create');
$this->assertSession()->statusCodeEquals(200);
$this->getSession()->getPage()->fillField('edit-label', "Generate image test derivative");
@ -55,7 +55,7 @@ class GenerateImageDerivativeTest extends GenerateDerivativeTestBase {
$this->getSession()->getPage()->fillField('edit-args', "-thumbnail 20x20");
$this->getSession()->getPage()->fillField('edit-scheme', "public");
$this->getSession()->getPage()->fillField('edit-path', "derp.jpeg");
$this->getSession()->getPage()->pressButton($this->t('Save'));
$this->getSession()->getPage()->pressButton('Save');
$this->assertSession()->statusCodeEquals(200);
// Create a context and add the action as a derivative reaction.
@ -71,7 +71,7 @@ class GenerateImageDerivativeTest extends GenerateDerivativeTestBase {
'field_media_use[0][target_id]' => $this->preservationMasterTerm->label(),
];
$this->drupalGet('media/add/' . $this->testMediaType->id());
$this->submitForm($values, $this->t('Save'));
$this->submitForm($values, 'Save');
$expected = [
'source_uri' => 'test_file.txt',

5
modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php

@ -48,8 +48,9 @@ class GenerateOCRDerivative extends AbstractGenerateDerivative {
*/
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') {
$mime = $form_state->getValue('mimetype');
$exploded_mime = explode('/', $mime);
if ($exploded_mime[0] != 'text' && $mime != 'application/xml') {
$form_state->setErrorByName(
'mimetype',
$this->t('Please enter file mimetype (e.g. text/plain.)')

5
modules/islandora_text_extraction/src/Plugin/Field/FieldFormatter/OcrTextFormatter.php

@ -132,8 +132,9 @@ class OcrTextFormatter extends FormatterBase implements ContainerFactoryPluginIn
$fileItem = $item->getValue();
$file = $this->entityTypeManager->getStorage('file')->load($fileItem['target_id']);
$contents = file_get_contents($file->getFileUri());
if (mb_detect_encoding($contents) != 'UTF-8') {
$contents = utf8_encode($contents);
$detected_encoding = mb_detect_encoding($contents);
if ($detected_encoding != 'UTF-8') {
$contents = mb_convert_encoding($contents, 'UTF-8', $detected_encoding);
}
$contents = nl2br($contents);
return $contents;

0
modules/islandora_text_extraction_defaults/config/install/core.entity_form_display.media.extracted_text.default.yml → modules/islandora_text_extraction_defaults/config/optional/core.entity_form_display.media.extracted_text.default.yml

0
modules/islandora_text_extraction_defaults/config/install/core.entity_view_display.media.extracted_text.default.yml → modules/islandora_text_extraction_defaults/config/optional/core.entity_view_display.media.extracted_text.default.yml

0
modules/islandora_text_extraction_defaults/config/install/field.field.media.extracted_text.field_edited_text.yml → modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_edited_text.yml

0
modules/islandora_text_extraction_defaults/config/install/field.field.media.extracted_text.field_media_file.yml → modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_media_file.yml

0
modules/islandora_text_extraction_defaults/config/install/field.field.media.extracted_text.field_media_of.yml → modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_media_of.yml

0
modules/islandora_text_extraction_defaults/config/install/field.field.media.extracted_text.field_media_use.yml → modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_media_use.yml

0
modules/islandora_text_extraction_defaults/config/install/field.field.media.extracted_text.field_mime_type.yml → modules/islandora_text_extraction_defaults/config/optional/field.field.media.extracted_text.field_mime_type.yml

0
modules/islandora_text_extraction_defaults/config/install/field.storage.media.field_edited_text.yml → modules/islandora_text_extraction_defaults/config/optional/field.storage.media.field_edited_text.yml

0
modules/islandora_text_extraction_defaults/config/install/language.content_settings.media.extracted_text.yml → modules/islandora_text_extraction_defaults/config/optional/language.content_settings.media.extracted_text.yml

0
modules/islandora_text_extraction_defaults/config/install/media.type.extracted_text.yml → modules/islandora_text_extraction_defaults/config/optional/media.type.extracted_text.yml

0
modules/islandora_text_extraction_defaults/config/install/rdf.mapping.media.extracted_text.yml → modules/islandora_text_extraction_defaults/config/optional/rdf.mapping.media.extracted_text.yml

0
modules/islandora_text_extraction_defaults/config/install/system.action.get_ocr_from_image.yml → modules/islandora_text_extraction_defaults/config/optional/system.action.get_ocr_from_image.yml

2
modules/islandora_text_extraction_defaults/islandora_text_extraction_defaults.features.yml

@ -1,2 +0,0 @@
bundle: islandora
required: true

6
modules/islandora_video/tests/src/Functional/GenerateVideoDerivativeTest.php

@ -37,7 +37,7 @@ class GenerateVideoDerivativeTest extends GenerateDerivativeTestBase {
// Create an action to generate a jpeg thumbnail.
$this->drupalGet('admin/config/system/actions');
$this->getSession()->getPage()->findById("edit-action")->selectOption("Generate a video derivative");
$this->getSession()->getPage()->pressButton($this->t('Create'));
$this->getSession()->getPage()->pressButton('Create');
$this->assertSession()->statusCodeEquals(200);
$this->getSession()->getPage()->fillField('edit-label', "Generate video test derivative");
@ -50,7 +50,7 @@ class GenerateVideoDerivativeTest extends GenerateDerivativeTestBase {
$this->getSession()->getPage()->fillField('edit-args', "-f mp4");
$this->getSession()->getPage()->fillField('edit-scheme', "public");
$this->getSession()->getPage()->fillField('edit-path', "derp.mov");
$this->getSession()->getPage()->pressButton($this->t('Save'));
$this->getSession()->getPage()->pressButton('Save');
$this->assertSession()->statusCodeEquals(200);
// Create a context and add the action as a derivative reaction.
@ -66,7 +66,7 @@ class GenerateVideoDerivativeTest extends GenerateDerivativeTestBase {
'field_media_use[0][target_id]' => $this->preservationMasterTerm->label(),
];
$this->drupalGet('media/add/' . $this->testMediaType->id());
$this->submitForm($values, $this->t('Save'));
$this->submitForm($values, 'Save');
$expected = [
'source_uri' => 'test_file.txt',

2
phpunit.xml

@ -47,7 +47,7 @@
<!-- Example for changing the driver args to phantomjs tests MINK_DRIVER_ARGS_PHANTOMJS value: '["http://127.0.0.1:8510"]' -->
<env name="MINK_DRIVER_ARGS_PHANTOMJS" value=""/>
<!-- Example for changing the driver args to webdriver tests MINK_DRIVER_ARGS_WEBDRIVER value: '["chrome", { "chromeOptions": { "w3c": false } }, "http://localhost:4444/wd/hub"]' For using the Firefox browser, replace "chrome" with "firefox" -->
<env name="MINK_DRIVER_ARGS_WEBDRIVER" value=""/>
<env name="MINK_DRIVER_ARGS_WEBDRIVER" value='["chrome", {"browserName":"chrome","chromeOptions":{"args":["--disable-gpu","--headless", "--no-sandbox", "--disable-dev-shm-usage"]}}, "http://localhost:9515"]'/>
</php>
<testsuites>
<testsuite name="unit">

2
src/Controller/ManageMembersController.php

@ -29,7 +29,7 @@ class ManageMembersController extends EntityController {
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManger;
protected $entityFieldManager;
/**
* The renderer.

15
src/EventGenerator/EventGenerator.php

@ -147,8 +147,19 @@ class EventGenerator implements EventGeneratorInterface {
}
}
unset($data["event"]);
unset($data["queue"]);
$allowed_keys = [
"file_upload_uri",
"fedora_uri",
"source_uri",
"destination_uri",
"args",
"mimetype",
"source_field",
];
$keys_to_unset = array_diff(array_keys($data), $allowed_keys);
foreach ($keys_to_unset as $key) {
unset($data[$key]);
}
if (!empty($data)) {
$event["attachment"] = [

25
src/Form/IslandoraSettingsForm.php

@ -43,6 +43,7 @@ class IslandoraSettingsForm extends ConfigFormBase {
];
const GEMINI_PSEUDO_FIELD = 'field_gemini_uri';
const NODE_DELETE_MEDIA_AND_FILES = 'delete_media_and_files';
const REDIRECT_AFTER_MEDIA_SAVE = 'redirect_after_media_save';
/**
* To list the available bundle types.
@ -128,6 +129,9 @@ class IslandoraSettingsForm extends ConfigFormBase {
'#type' => 'textfield',
'#title' => $this->t('URL'),
'#default_value' => $config->get(self::BROKER_URL),
'#config' => [
'key' => 'islandora.settings:' . self::BROKER_URL,
],
];
$broker_user = $config->get(self::BROKER_USER);
$form['broker_info']['provide_user_creds'] = [
@ -148,6 +152,9 @@ class IslandoraSettingsForm extends ConfigFormBase {
$state_selector => ['checked' => TRUE],
],
],
'#config' => [
'key' => 'islandora.settings:' . self::BROKER_USER,
],
];
$form['broker_info'][self::BROKER_PASSWORD] = [
'#type' => 'password',
@ -158,6 +165,10 @@ class IslandoraSettingsForm extends ConfigFormBase {
$state_selector => ['checked' => TRUE],
],
],
'#config' => [
'key' => 'islandora.settings:' . self::BROKER_PASSWORD,
'secret' => TRUE,
],
];
$form[self::JWT_EXPIRY] = [
'#type' => 'textfield',
@ -210,10 +221,21 @@ class IslandoraSettingsForm extends ConfigFormBase {
'#default_value' => (bool) $config->get(self::NODE_DELETE_MEDIA_AND_FILES),
];
$form[self::REDIRECT_AFTER_MEDIA_SAVE] = [
'#type' => 'checkbox',
'#title' => $this->t('Redirect after media save.'),
'#description' => $this->t('Redirect to node-specific media list after creation of media.'),
'#default_value' => (bool) $config->get(self::REDIRECT_AFTER_MEDIA_SAVE),
];
$form[self::FEDORA_URL] = [
'#type' => 'textfield',
'#title' => $this->t('Fedora URL'),
'#attributes' => ['readonly' => 'readonly'],
'#description' => $this->t('Read-only. This value is set in settings.php as the URL for the Fedora flysystem.'),
'#attributes' => [
'readonly' => 'readonly',
'disabled' => 'disabled',
],
'#default_value' => $fedora_url,
];
@ -361,6 +383,7 @@ class IslandoraSettingsForm extends ConfigFormBase {
->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))
->set(self::REDIRECT_AFTER_MEDIA_SAVE, $form_state->getValue(self::REDIRECT_AFTER_MEDIA_SAVE))
->save();
parent::submitForm($form, $form_state);

2
src/IslandoraContextManager.php

@ -37,7 +37,7 @@ class IslandoraContextManager extends ContextManager {
}
/** @var \Drupal\context\ContextInterface $context */
foreach ($this->getContexts() as $context) {
if ($this->evaluateContextConditions($context, $provided) && !$context->disabled()) {
if (!$context->disabled() && $this->evaluateContextConditions($context, $provided)) {
$this->activeContexts[$context->id()] = $context;
}
}

6
src/Plugin/Condition/NodeHasParent.php

@ -137,9 +137,11 @@ class NodeHasParent extends ConditionPluginBase implements ContainerFactoryPlugi
* TRUE if entity references the specified parent.
*/
protected function evaluateEntity(EntityInterface $entity) {
$parent_reference_field = $this->configuration['parent_reference_field'];
foreach ($entity->referencedEntities() as $referenced_entity) {
if ($entity->getEntityTypeID() == 'node' && $referenced_entity->getEntityTypeId() == 'node') {
$parent_reference_field = $this->configuration['parent_reference_field'];
// Check whether the entity and the referenced entity are nodes.
// Also make sure that the field exists.
if ($entity->getEntityTypeID() == 'node' && $entity->hasField($parent_reference_field) && $referenced_entity->getEntityTypeId() == 'node') {
$field = $entity->get($parent_reference_field);
if (!$field->isEmpty()) {
$nids = $field->getValue();

6
src/Plugin/Field/FieldFormatter/IslandoraImageFormatter.php

@ -5,7 +5,7 @@ namespace Drupal\islandora\Plugin\Field\FieldFormatter;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\File\FileUrlGenerator;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatter;
use Drupal\islandora\IslandoraUtils;
@ -57,7 +57,7 @@ class IslandoraImageFormatter extends ImageFormatter {
* The image style storage.
* @param \Drupal\islandora\IslandoraUtils $utils
* Islandora utils.
* @param \Drupal\Core\File\FileUrlGenerator $file_url_generator
* @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
* The File URL Generator.
*/
public function __construct(
@ -71,7 +71,7 @@ class IslandoraImageFormatter extends ImageFormatter {
AccountInterface $current_user,
EntityStorageInterface $image_style_storage,
IslandoraUtils $utils,
FileUrlGenerator $file_url_generator
FileUrlGeneratorInterface $file_url_generator
) {
parent::__construct(
$plugin_id,

74
src/Plugin/views/filter/NodeHasMediaUse.php

@ -2,8 +2,13 @@
namespace Drupal\islandora\Plugin\views\filter;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\islandora\IslandoraUtils;
use Drupal\views\Plugin\views\filter\FilterPluginBase;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Views Filter on Having Media of a Type.
@ -14,6 +19,48 @@ use Drupal\views\Plugin\views\filter\FilterPluginBase;
*/
class NodeHasMediaUse extends FilterPluginBase {
/**
* Islandora's utility service.
*
* @var \Drupal\islandora\IslandoraUtils
*/
protected IslandoraUtils $utils;
/**
* Drupal's entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* Drupal's database connection service.
*
* @var \Drupal\Core\Database\Connection
*/
protected Connection $connection;
/**
* Logger service.
*
* @var \Psr\Log\LoggerInterface
*/
protected LoggerInterface $logger;
/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->utils = $container->get('islandora.utils');
$instance->entityTypeManager = $container->get('entity_type.manager');
$instance->connection = $container->get('database');
$instance->logger = $container->get('logger.factory')->get('islanodra');
return $instance;
}
/**
* {@inheritdoc}
*/
@ -29,7 +76,7 @@ class NodeHasMediaUse extends FilterPluginBase {
*/
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
$uri = $form_state->getValues()['options']['use_uri'];
$term = \Drupal::service('islandora.utils')->getTermForUri($uri);
$term = $this->utils->getTermForUri($uri);
if (empty($term)) {
$form_state->setError($form['use_uri'], $this->t('Could not find term with URI: "%uri"', ['%uri' => $uri]));
}
@ -39,7 +86,7 @@ class NodeHasMediaUse extends FilterPluginBase {
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['vid' => 'islandora_media_use']);
$terms = $this->entityTypeManager->getStorage('taxonomy_term')->loadByProperties(['vid' => 'islandora_media_use']);
$uris = [];
foreach ($terms as $term) {
foreach ($term->get('field_external_uri')->getValue() as $uri) {
@ -67,7 +114,7 @@ class NodeHasMediaUse extends FilterPluginBase {
*/
public function adminSummary() {
$operator = ($this->options['negated']) ? "does not have" : "has";
$term = \Drupal::service('islandora.utils')->getTermForUri($this->options['use_uri']);
$term = $this->utils->getTermForUri($this->options['use_uri']);
$label = (empty($term)) ? 'BROKEN TERM URI' : $term->label();
return "Node {$operator} a '{$label}' media";
}
@ -77,18 +124,21 @@ class NodeHasMediaUse extends FilterPluginBase {
*/
public function query() {
$condition = ($this->options['negated']) ? 'NOT IN' : 'IN';
$utils = \Drupal::service('islandora.utils');
$term = $utils->getTermForUri($this->options['use_uri']);
$term = $this->utils->getTermForUri($this->options['use_uri']);
if (empty($term)) {
\Drupal::logger('islandora')->warning('Node Has Media Filter could not find term with URI: "%uri"', ['%uri' => $this->options['use_uri']]);
$this->logger->warning('Node Has Media Filter could not find term with URI: "%uri"', ['%uri' => $this->options['use_uri']]);
return;
}
$sub_query = \Drupal::database()->select('media', 'm');
$sub_query->join('media__field_media_use', 'use', 'm.mid = use.entity_id');
$sub_query->join('media__field_media_of', 'of', 'm.mid = of.entity_id');
$sub_query->fields('of', ['field_media_of_target_id'])
->condition('use.field_media_use_target_id', $term->id());
$this->query->addWhere(0, 'nid', $sub_query, $condition);
$sub_query = $this->connection->select('media', 'm');
$use_alias = $sub_query->join('media__field_media_use', 'use', 'm.mid = %alias.entity_id');
$of_alias = $sub_query->join('media__field_media_of', 'of', 'm.mid = %alias.entity_id');
$sub_query->fields($of_alias, ['field_media_of_target_id'])
->condition("{$use_alias}.field_media_use_target_id", $term->id());
/** @var \Drupal\views\Plugin\views\query\Sql $query */
$query = $this->query;
$alias = $query->ensureTable('node_field_data', $this->relationship);
$query->addWhere(0, "{$alias}.nid", $sub_query, $condition);
}
}

29
src/PresetReaction/PresetReaction.php

@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@ -21,12 +22,20 @@ class PresetReaction extends ContextReactionPluginBase implements ContainerFacto
*/
protected $actionStorage;
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $action_storage) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $action_storage, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->actionStorage = $action_storage;
$this->logger = $logger;
}
/**
@ -37,7 +46,8 @@ class PresetReaction extends ContextReactionPluginBase implements ContainerFacto
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')->getStorage('action')
$container->get('entity_type.manager')->getStorage('action'),
$container->get('logger.factory')->get('islandora')
);
}
@ -56,7 +66,20 @@ class PresetReaction extends ContextReactionPluginBase implements ContainerFacto
$action_ids = $config['actions'];
foreach ($action_ids as $action_id) {
$action = $this->actionStorage->load($action_id);
$action->execute([$entity]);
if (empty($action)) {
$this->logger->warning('Action "@action" not found.', ['@action' => $action_id]);
continue;
}
try {
$action->execute([$entity]);
}
catch (\Exception $e) {
$this->logger->error('Error executing action "@action" on entity "@entity": @message', [
'@action' => $action->label(),
'@entity' => $entity->label(),
'@message' => $e->getMessage(),
]);
}
}
}

221
tests/modules/integer_weight_test_views/test_views/views.view.test_integer_weight.yml

@ -4,6 +4,7 @@ dependencies:
config:
- node.type.repo_item
module:
- islandora
- node
- user
id: test_integer_weight
@ -13,87 +14,36 @@ description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
display_plugin: default
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
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: table
row:
type: fields
title: 'test weight'
fields:
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
entity_type: node
entity_field: title
plugin_id: field
label: Title
exclude: false
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
trim: false
html: false
hide_empty: false
empty_zero: false
settings:
link_to_entity: true
plugin_id: field
relationship: none
group_type: group
admin_label: ''
label: Title
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
@ -103,9 +53,13 @@ display:
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: string
settings:
link_to_entity: true
group_column: value
group_columns: { }
group_rows: true
@ -123,7 +77,8 @@ display:
relationship: none
group_type: group
admin_label: ''
label: 'Integer weight selector (field_integer_weight)'
plugin_id: integer_weight_selector
label: 'Integer Weight Selector (field_integer_weight)'
exclude: false
alter:
alter_text: false
@ -164,44 +119,57 @@ display:
hide_empty: false
empty_zero: false
hide_alter_empty: true
range: '20'
plugin_id: integer_weight_selector
filters:
status:
value: '1'
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
pager:
type: mini
options:
offset: 0
items_per_page: 10
total_pages: null
id: 0
tags:
next: ››
previous: ‹‹
expose:
operator: ''
group: 1
type:
id: type
table: node_field_data
field: type
value:
repo_item:repo_item
entity_type: node
entity_field: type
plugin_id: bundle
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: 'access content'
cache:
type: tag
options: { }
empty: { }
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
entity_type: node
entity_field: created
plugin_id: date
order: DESC
expose:
label: ''
exposed: false
granularity: second
field_integer_weight_value:
id: field_integer_weight_value
@ -210,17 +178,82 @@ display:
relationship: none
group_type: group
admin_label: ''
plugin_id: standard
order: ASC
expose:
label: ''
field_identifier: ''
exposed: false
arguments: { }
filters:
status:
id: status
table: node_field_data
field: status
entity_type: node
entity_field: status
plugin_id: boolean
value: '1'
group: 1
expose:
operator: ''
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
entity_type: node
entity_field: type
plugin_id: bundle
operator: in
value:
repo_item: repo_item
group: 1
exposed: false
expose:
operator_id: ''
label: ''
plugin_id: standard
title: 'test weight'
description: ''
use_operator: false
operator: ''
operator_limit_selection: false
operator_list: { }
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
style:
type: table
row:
type: fields
query:
type: views_query
options:
query_comment: ''
disable_sql_rewrite: false
distinct: false
replica: false
query_tags: { }
relationships: { }
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
@ -232,9 +265,9 @@ display:
- user.permissions
tags: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
display_plugin: page
position: 1
display_options:
display_extenders: { }

8
tests/src/Functional/AddChildTest.php

@ -9,13 +9,19 @@ namespace Drupal\Tests\islandora\Functional;
*/
class AddChildTest extends IslandoraFunctionalTestBase {
/**
* The taxonomy term representing "Collection" items.
*
* @var \Drupal\taxonomy\TermInterface
*/
protected $collectionTerm;
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->parent =
$this->collectionTerm = $this->container->get('entity_type.manager')->getStorage('taxonomy_term')->create([
'name' => 'Collection',
'vid' => $this->testVocabulary->id(),

4
tests/src/Functional/ContentEntityTypeTest.php

@ -39,7 +39,7 @@ class ContentEntityTypeTest extends IslandoraFunctionalTestBase {
$this->addCondition('test', 'content_entity_type');
$this->getSession()->getPage()->checkField("edit-conditions-content-entity-type-types-node");
$this->getSession()->getPage()->findById("edit-conditions-content-entity-type-context-mapping-node")->selectOption("@node.node_route_context:node");
$this->getSession()->getPage()->pressButton($this->t('Save and continue'));
$this->getSession()->getPage()->pressButton('Save and continue');
$this->addPresetReaction('test', 'index', 'hello_world');
// Create a new node confirm Hello World! is printed to the screen.
@ -53,7 +53,7 @@ class ContentEntityTypeTest extends IslandoraFunctionalTestBase {
'files[field_media_file_0]' => __DIR__ . '/../../fixtures/test_file.txt',
];
$this->drupalGet('media/add/' . $this->testMediaType->id());
$this->submitForm($values, $this->t('Save'));
$this->submitForm($values, 'Save');
$this->assertSession()->pageTextNotContains("Hello World!");
}

6
tests/src/Functional/DerivativeReactionTest.php

@ -53,7 +53,7 @@ class DerivativeReactionTest extends IslandoraFunctionalTestBase {
'field_media_of[0][target_id]' => 'Test Node',
];
$this->drupalGet('media/add/' . $this->testMediaType->id());
$this->submitForm($values, $this->t('Save'));
$this->submitForm($values, 'Save');
// field_media_of is set and there's a file, so derivatives should fire.
$this->assertSession()->pageTextContains("Hello World!");
@ -71,9 +71,9 @@ class DerivativeReactionTest extends IslandoraFunctionalTestBase {
'files[field_media_file_0]' => __DIR__ . '/../../fixtures/test_file2.txt',
];
$this->drupalGet($media_url . '/edit');
$this->getSession()->getPage()->pressButton($this->t('Remove'));
$this->getSession()->getPage()->pressButton('Remove');
$this->getSession()->getPage()->fillField('files[field_media_file_0]', __DIR__ . '/../../fixtures/test_file2.txt');
$this->getSession()->getPage()->pressButton($this->t('Save'));
$this->getSession()->getPage()->pressButton('Save');
$this->assertSession()->pageTextContains("Hello World!");
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save