diff --git a/composer.json b/composer.json index 100dfef3d..e3f766153 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ ], "require": { "drupal/inline_entity_form": "^1.0@beta", - "drupal/rules": "3.x-dev", + "drupal/context": "^4.0", "drupal/search_api": "^1.0@beta", "islandora/jsonld": "dev-8.x-1.x", "stomp-php/stomp-php": "4.*", diff --git a/config/install/context.context.file.yml b/config/install/context.context.file.yml new file mode 100644 index 000000000..5cc17829f --- /dev/null +++ b/config/install/context.context.file.yml @@ -0,0 +1,34 @@ +uuid: 6804c3b4-a33e-448c-97cc-cfcab3afe7c6 +langcode: en +status: true +dependencies: + enforced: + module: + - islandora + module: + - islandora +name: file +label: File +group: Islandora +description: 'Reactions for all Files' +requireAllConditions: false +disabled: false +conditions: + is_file: + id: is_file + negate: 0 + uuid: a98d439f-5512-4e60-965c-b215b8f78438 + context_mapping: + file: '@islandora.file_route_context_provider:file' +reactions: + index: + id: index + actions: + index_file_in_fedora: index_file_in_fedora + saved: false + delete: + id: delete + actions: + delete_file_from_fedora: delete_file_from_fedora + saved: false +weight: 0 diff --git a/config/install/context.context.media.yml b/config/install/context.context.media.yml new file mode 100644 index 000000000..3b0af476d --- /dev/null +++ b/config/install/context.context.media.yml @@ -0,0 +1,35 @@ +d: c14bfcb1-7e62-4a3c-98e9-0cdbadbe5c45 +langcode: en +status: true +dependencies: + enforced: + module: + - islandora + module: + - islandora +name: media +label: Media +group: Islandora +description: 'Reactions for all Media' +requireAllConditions: false +disabled: false +conditions: + is_media: + id: is_media + negate: 0 + uuid: 2e291ec1-11ee-4c36-ba7e-cb05128bf27d + context_mapping: + media: '@islandora.media_route_context_provider:media' +reactions: + index: + id: index + actions: + index_media_in_fedora: index_media_in_fedora + index_media_in_triplestore: index_media_in_triplestore + saved: false + delete: + id: delete + actions: + delete_media_from_triplestore: delete_media_from_triplestore + saved: false +weight: 0 diff --git a/config/install/context.context.node.yml b/config/install/context.context.node.yml new file mode 100644 index 000000000..434d5b4ec --- /dev/null +++ b/config/install/context.context.node.yml @@ -0,0 +1,36 @@ +d: 48525bb3-36a2-449a-92ed-1ab3e94b3da0 +langcode: en +status: true +dependencies: + enforced: + module: + - islandora + module: + - islandora +name: node +label: Node +group: Islandora +description: 'Reactions for all Nodes' +requireAllConditions: false +disabled: false +conditions: + is_node: + id: is_node + negate: 0 + uuid: f25d55aa-1664-4202-b846-afd20b527da2 + context_mapping: + node: '@node.node_route_context:node' +reactions: + index: + id: index + actions: + index_node_in_fedora: index_node_in_fedora + index_node_in_triplestore: index_node_in_triplestore + saved: false + delete: + id: delete + actions: + delete_node_from_fedora: delete_node_from_fedora + delete_node_from_triplestore: delete_node_from_triplestore + saved: false +weight: 0 diff --git a/config/install/rules.reaction.broadcast_content_create_event.yml b/config/install/rules.reaction.broadcast_content_create_event.yml deleted file mode 100644 index 4265178ca..000000000 --- a/config/install/rules.reaction.broadcast_content_create_event.yml +++ /dev/null @@ -1,51 +0,0 @@ -uuid: b8d1db0c-be8f-47a7-889f-ac710db2e18a -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_content_create_event -label: 'Broadcast Content Create Event' -events: - - - event_name: 'rules_entity_insert:node' -description: 'Broadcasts an AS2 event to a message broker when Content is created.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: 40cabb74-fcc7-4498-90f9-3a4ec71b3710 - conditions: - id: rules_and - uuid: 8e0d7b29-15f4-448d-b79a-d85ef97d274e - conditions: { } - actions: - id: rules_action_set - uuid: 0f832259-2aa1-45a4-83df-d9e0ff4c7edd - actions: - - - id: rules_action - uuid: 922264b9-3db1-42eb-9e01-e781a58a3695 - context_values: { } - context_mapping: - entity: node - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_create_event_generator - - - id: rules_action - uuid: 0e953790-c751-4de8-99b3-c729ba1e09e3 - context_values: - recipients: - - "activemq:queue:islandora-indexing-fcrepo-content\r" - - 'activemq:queue:islandora-indexing-triplestore-index' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_content_delete_event.yml b/config/install/rules.reaction.broadcast_content_delete_event.yml deleted file mode 100644 index f6c989aa7..000000000 --- a/config/install/rules.reaction.broadcast_content_delete_event.yml +++ /dev/null @@ -1,51 +0,0 @@ -uuid: 752003c1-8d98-4d33-b6d3-2bdde52e77bf -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_content_delete_event -label: 'Broadcast Content Delete Event' -events: - - - event_name: 'rules_entity_delete:node' -description: 'Broadcasts an AS2 event to a message broker when Content is deleted.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: b5ca11c1-f80c-4dce-a9f7-9d5db0fec971 - conditions: - id: rules_and - uuid: ede4e2b7-ce4c-4a9d-a5ff-a18a248ccd4c - conditions: { } - actions: - id: rules_action_set - uuid: 7c96bc08-7b7e-499d-8535-a2c735f6b98b - actions: - - - id: rules_action - uuid: 36647c5b-3355-4d4b-8550-5b0170b98ad1 - context_values: { } - context_mapping: - entity: node - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_delete_event_generator - - - id: rules_action - uuid: 9257b59c-466c-43d7-8690-62dd87a053eb - context_values: - recipients: - - "activemq:queue:islandora-indexing-fcrepo-delete\r" - - 'activemq:queue:islandora-indexing-triplestore-delete' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_content_update_event.yml b/config/install/rules.reaction.broadcast_content_update_event.yml deleted file mode 100644 index 614720c73..000000000 --- a/config/install/rules.reaction.broadcast_content_update_event.yml +++ /dev/null @@ -1,51 +0,0 @@ -uuid: 9eeb9a6a-d3ba-41b3-9f1f-68bd016fe8b1 -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_content_update_event -label: 'Broadcast Content Update Event' -events: - - - event_name: 'rules_entity_update:node' -description: 'Broadcasts an AS2 event to a message broker when Content is updated.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: 55f8a158-3fe4-48bb-92f2-ba53630d56f3 - conditions: - id: rules_and - uuid: 8269d20f-cb56-4399-8c87-17eb64bfe5eb - conditions: { } - actions: - id: rules_action_set - uuid: 567aca08-456f-449e-a91b-b17a21366bdf - actions: - - - id: rules_action - uuid: ee51523e-3bba-43a5-95ce-e998fb3392d3 - context_values: { } - context_mapping: - entity: node - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_update_event_generator - - - id: rules_action - uuid: 7b9cf7be-40e4-4490-ae6f-07a84eb112c4 - context_values: - recipients: - - "activemq:queue:islandora-indexing-fcrepo-content\r" - - 'activemq:queue:islandora-indexing-triplestore-index' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_file_create_event.yml b/config/install/rules.reaction.broadcast_file_create_event.yml deleted file mode 100644 index cf1379f50..000000000 --- a/config/install/rules.reaction.broadcast_file_create_event.yml +++ /dev/null @@ -1,50 +0,0 @@ -uuid: 5a444d61-ac7f-4cde-a8b7-2693bd825753 -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_file_create_event -label: 'Broadcast File Create Event' -events: - - - event_name: 'rules_entity_insert:file' -description: 'Broadcasts an AS2 event to a message broker when a File is created.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: 54c6585d-453d-4143-8e54-760019f251d5 - conditions: - id: rules_and - uuid: d82f7041-6522-4127-9676-d5534f7c1684 - conditions: { } - actions: - id: rules_action_set - uuid: 0dc80d3b-2a60-4a47-afd6-4026d0fdffe6 - actions: - - - id: rules_action - uuid: 0e42b62d-39ca-4f51-baa5-fdd1b37605fe - context_values: { } - context_mapping: - entity: file - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_create_event_generator - - - id: rules_action - uuid: bcbbe914-54a9-4ff2-9d4b-98945682e087 - context_values: - recipients: - - 'activemq:queue:islandora-indexing-fcrepo-file' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_file_delete_event.yml b/config/install/rules.reaction.broadcast_file_delete_event.yml deleted file mode 100644 index c8016eaa8..000000000 --- a/config/install/rules.reaction.broadcast_file_delete_event.yml +++ /dev/null @@ -1,50 +0,0 @@ -uuid: d35441d4-62d6-4e0d-bf6f-23ff32eab457 -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_file_delete_event -label: 'Broadcast File Delete Event' -events: - - - event_name: 'rules_entity_delete:file' -description: 'Broadcasts an AS2 event to a message broker when a File is deleted.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: 69e8870c-9d20-4cc3-9a17-de940d4c9932 - conditions: - id: rules_and - uuid: f465ad23-88a2-4026-a7ca-dbfc2d3aa031 - conditions: { } - actions: - id: rules_action_set - uuid: 65ce1b3b-7986-4cf2-ab03-b950212f505e - actions: - - - id: rules_action - uuid: 2d6b2435-e986-4e53-8831-e4328aa63af3 - context_values: { } - context_mapping: - entity: file - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_delete_event_generator - - - id: rules_action - uuid: f1a6a455-5486-4a4a-a3c9-4e9b3867cf64 - context_values: - recipients: - - 'activemq:queue:islandora-indexing-fcrepo-delete' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_file_update_event.yml b/config/install/rules.reaction.broadcast_file_update_event.yml deleted file mode 100644 index fc2755a75..000000000 --- a/config/install/rules.reaction.broadcast_file_update_event.yml +++ /dev/null @@ -1,50 +0,0 @@ -d: 129d52bf-c67f-41fc-81fc-83f126f59a66 -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_file_update_event -label: 'Broadcast File Update Event' -events: - - - event_name: 'rules_entity_update:file' -description: 'Broadcasts an AS2 event to a message broker when a File is updated.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: 5355a324-0af0-48bb-8168-e2810a9ee0a2 - conditions: - id: rules_and - uuid: 0b266024-65ea-4e91-b0e6-ae88b8bfd5ed - conditions: { } - actions: - id: rules_action_set - uuid: 85a784ad-7f03-4ba9-8c01-f87f33f15d5e - actions: - - - id: rules_action - uuid: a7dcf8e2-7e2d-4c9b-b658-e4f3f28898a1 - context_values: { } - context_mapping: - entity: file - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_update_event_generator - - - id: rules_action - uuid: 60aa1b60-9ea4-40d1-bfbf-d036a617179a - context_values: - recipients: - - 'activemq:queue:islandora-indexing-fcrepo-file' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_media_create_event.yml b/config/install/rules.reaction.broadcast_media_create_event.yml deleted file mode 100644 index 5ea4799f6..000000000 --- a/config/install/rules.reaction.broadcast_media_create_event.yml +++ /dev/null @@ -1,51 +0,0 @@ -uuid: 4474df44-01ee-4abf-84f9-9aa41d787d27 -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_media_create_event -label: 'Broadcast Media Create Event' -events: - - - event_name: 'rules_entity_insert:media' -description: 'Broadcasts an AS2 event to a message broker when Media is created.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: d4ba4cc1-3b18-400d-867f-1605d72d9717 - conditions: - id: rules_and - uuid: 9ccf9d29-89be-4b1d-8417-230e33f8fd6f - conditions: { } - actions: - id: rules_action_set - uuid: 47afb6b3-e39e-4c3a-af47-669e963353a2 - actions: - - - id: rules_action - uuid: dff4ebfb-84c5-4d0f-acf7-62e3edbab143 - context_values: { } - context_mapping: - entity: media - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_create_event_generator - - - id: rules_action - uuid: 6b0d07b3-048e-43ac-8a9f-2c5203f8080e - context_values: - recipients: - - "activemq:queue:islandora-indexing-fcrepo-media\r" - - "activemq:queue:islandora-indexing-triplestore-index" - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_media_delete_event.yml b/config/install/rules.reaction.broadcast_media_delete_event.yml deleted file mode 100644 index 59065e48e..000000000 --- a/config/install/rules.reaction.broadcast_media_delete_event.yml +++ /dev/null @@ -1,50 +0,0 @@ -uuid: af85f943-2cc0-455c-97b0-4035d15f55ec -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_media_delete_event -label: 'Broadcast Media Delete Event' -events: - - - event_name: 'rules_entity_delete:media' -description: 'Broadcasts an AS2 event to a message broker when Media is deleted.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: abb78ad6-5f27-43e7-890c-c2a12e76ce51 - conditions: - id: rules_and - uuid: 8c386012-6796-4138-b4e7-d438916c713f - conditions: { } - actions: - id: rules_action_set - uuid: 6599d3f0-dcd7-482c-bcb4-fa76b012da6a - actions: - - - id: rules_action - uuid: 7003fe72-49f7-4a3a-b95b-781ef1c61615 - context_values: { } - context_mapping: - entity: media - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_delete_event_generator - - - id: rules_action - uuid: 8a5dc149-9629-4e94-a8d5-3ff6069d6af6 - context_values: - recipients: - - 'activemq:queue:islandora-indexing-triplestore-delete' - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/rules.reaction.broadcast_media_update_event.yml b/config/install/rules.reaction.broadcast_media_update_event.yml deleted file mode 100644 index 5673dedb7..000000000 --- a/config/install/rules.reaction.broadcast_media_update_event.yml +++ /dev/null @@ -1,51 +0,0 @@ -uuid: d5d823ce-cfd0-4e9c-85c9-9090660d831e -langcode: en -status: true -dependencies: - enforced: - module: - - islandora -id: broadcast_media_update_event -label: 'Broadcast Media Update Event' -events: - - - event_name: 'rules_entity_update:media' -description: 'Broadcasts an AS2 event to a message broker when Media is updated.' -tags: - - '' -config_version: '3' -expression: - id: rules_rule - uuid: 3fb05cc7-f27a-4a79-8e98-544e4aabaf15 - conditions: - id: rules_and - uuid: 585b55af-847d-447a-afee-01b855807c4a - conditions: { } - actions: - id: rules_action_set - uuid: bb96d589-0d63-4b1b-89d7-faf358171d40 - actions: - - - id: rules_action - uuid: 60a1f348-f85f-45fc-a785-b279b522863a - context_values: { } - context_mapping: - entity: media - user: '@user.current_user_context:current_user' - context_processors: { } - provides_mapping: { } - action_id: islandora_update_event_generator - - - id: rules_action - uuid: ee50c8ae-a9cd-479a-aa86-3567629a01b8 - context_values: - recipients: - - "activemq:queue:islandora-indexing-fcrepo-media\r" - - "activemq:queue:islandora-indexing-triplestore-index" - context_mapping: - message: event_message - context_processors: - recipients: - rules_tokens: { } - provides_mapping: { } - action_id: islandora_broadcast diff --git a/config/install/system.action.delete_file_from_fedora.yml b/config/install/system.action.delete_file_from_fedora.yml new file mode 100644 index 000000000..ee61cf04f --- /dev/null +++ b/config/install/system.action.delete_file_from_fedora.yml @@ -0,0 +1,16 @@ +uuid: 76d619dd-54f1-4047-8e89-54d5f1a7c16a +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: delete_file_from_fedora +label: 'Delete File from Fedora' +type: file +plugin: emit_file_event +configuration: + queue: 'islandora-indexing-fcrepo-delete' + event: delete diff --git a/config/install/system.action.delete_media_from_triplestore.yml b/config/install/system.action.delete_media_from_triplestore.yml new file mode 100644 index 000000000..3a67fe152 --- /dev/null +++ b/config/install/system.action.delete_media_from_triplestore.yml @@ -0,0 +1,16 @@ +uuid: a5f0a427-9c30-41ec-92b8-04b47855aee1 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: delete_media_from_triplestore +label: 'Delete Media from Triplestore' +type: media +plugin: emit_media_event +configuration: + queue: 'islandora-indexing-triplestore-delete' + event: delete diff --git a/config/install/system.action.delete_node_from_fedora.yml b/config/install/system.action.delete_node_from_fedora.yml new file mode 100644 index 000000000..ed1d891af --- /dev/null +++ b/config/install/system.action.delete_node_from_fedora.yml @@ -0,0 +1,16 @@ +uuid: 23ad55f4-301b-4ffb-b542-4cf2c0c291d8 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: delete_node_from_fedora +label: 'Delete Node from Fedora' +type: node +plugin: emit_node_event +configuration: + queue: 'islandora-indexing-fcrepo-delete' + event: delete diff --git a/config/install/system.action.delete_node_from_triplestore.yml b/config/install/system.action.delete_node_from_triplestore.yml new file mode 100644 index 000000000..4fc9bae0d --- /dev/null +++ b/config/install/system.action.delete_node_from_triplestore.yml @@ -0,0 +1,16 @@ +uuid: 4340c20a-d314-4cbf-a26f-c36d7180ede5 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: delete_node_from_triplestore +label: 'Delete Node from Triplestore' +type: node +plugin: emit_node_event +configuration: + queue: 'islandora-indexing-triplestore-delete' + event: delete diff --git a/config/install/system.action.index_file_in_fedora.yml b/config/install/system.action.index_file_in_fedora.yml new file mode 100644 index 000000000..d1c98111d --- /dev/null +++ b/config/install/system.action.index_file_in_fedora.yml @@ -0,0 +1,16 @@ +uuid: 526d2857-de6f-472d-87e2-d8726db72301 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: index_file_in_fedora +label: 'Index File in Fedora' +type: file +plugin: emit_file_event +configuration: + queue: 'islandora-indexing-fcrepo-file' + event: update diff --git a/config/install/system.action.index_media_in_fedora.yml b/config/install/system.action.index_media_in_fedora.yml new file mode 100644 index 000000000..7cd560d23 --- /dev/null +++ b/config/install/system.action.index_media_in_fedora.yml @@ -0,0 +1,16 @@ +d: 27ce85fc-a9fe-46f5-b518-5af1126e2368 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: index_media_in_fedora +label: 'Index Media in Fedora' +type: media +plugin: emit_media_event +configuration: + queue: 'islandora-indexing-fcrepo-media' + event: update diff --git a/config/install/system.action.index_media_in_triplestore.yml b/config/install/system.action.index_media_in_triplestore.yml new file mode 100644 index 000000000..2c7737b4b --- /dev/null +++ b/config/install/system.action.index_media_in_triplestore.yml @@ -0,0 +1,16 @@ +uuid: f7c9169d-6556-4720-b225-11a09581272e +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: index_media_in_triplestore +label: 'Index Media in Triplestore' +type: media +plugin: emit_media_event +configuration: + queue: 'islandora-indexing-triplestore-index' + event: update diff --git a/config/install/system.action.index_node_in_fedora.yml b/config/install/system.action.index_node_in_fedora.yml new file mode 100644 index 000000000..9dbdf592c --- /dev/null +++ b/config/install/system.action.index_node_in_fedora.yml @@ -0,0 +1,16 @@ +uuid: edb74080-7cf3-45e7-97e2-78cd7494ea92 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: index_node_in_fedora +label: 'Index Node in Fedora' +type: node +plugin: emit_node_event +configuration: + queue: 'islandora-indexing-fcrepo-content' + event: update diff --git a/config/install/system.action.index_node_in_triplestore.yml b/config/install/system.action.index_node_in_triplestore.yml new file mode 100644 index 000000000..c604b3fec --- /dev/null +++ b/config/install/system.action.index_node_in_triplestore.yml @@ -0,0 +1,16 @@ +uuid: 5012a177-307c-4ee0-a986-cd35d76f2a58 +langcode: en +status: true +dependencies: + module: + - islandora + enforced: + module: + - islandora +id: index_node_in_triplestore +label: 'Index Node in Triplestore' +type: node +plugin: emit_node_event +configuration: + queue: 'islandora-indexing-triplestore-index' + event: update diff --git a/config/install/views.view.file_checksum.yml b/config/install/views.view.file_checksum.yml index e7526fdbf..a3091a178 100644 --- a/config/install/views.view.file_checksum.yml +++ b/config/install/views.view.file_checksum.yml @@ -9,6 +9,9 @@ dependencies: - rest - serialization - user + enforced: + module: + - islandora _core: default_config_hash: e7XqQa-N16XDqeDTA7Ohgx6iLb6mIQ1RUs0krFFIbAw id: file_checksum diff --git a/config/schema/islandora.schema.yml b/config/schema/islandora.schema.yml index 6c88ccbcb..4f9cbda86 100644 --- a/config/schema/islandora.schema.yml +++ b/config/schema/islandora.schema.yml @@ -11,3 +11,48 @@ islandora.settings: broadcast_queue: type: string label: 'Queue that handles distributing messages amongst multiple recipients' + +action.configuration.emit_node_event: + type: mapping + label: 'Emit a Node event to a queue/topic' + mapping: + queue: + type: text + label: 'Queue' + event: + type: text + label: 'Event Type' + +action.configuration.emit_media_event: + type: mapping + label: 'Emit a Media event to a queue/topic' + mapping: + queue: + type: text + label: 'Queue' + event: + type: text + label: 'Event Type' + +action.configuration.emit_file_event: + type: mapping + label: 'Emit a Flie event to a queue/topic' + mapping: + queue: + type: text + label: 'Queue' + event: + type: text + label: 'Event Type' + +condition.plugin.is_node: + type: condition.plugin + mapping: + +condition.plugin.is_media: + type: condition.plugin + mapping: + +condition.plugin.is_file: + type: condition.plugin + mapping: diff --git a/islandora.info.yml b/islandora.info.yml index e33fc6627..fd0d81ace 100644 --- a/islandora.info.yml +++ b/islandora.info.yml @@ -13,10 +13,11 @@ dependencies: - options - inline_entity_form - jsonld - - rules - search_api - jwt - media_entity_image - rest - filehash - basic_auth + - context + - action diff --git a/islandora.module b/islandora.module index e44434e21..495f61271 100644 --- a/islandora.module +++ b/islandora.module @@ -14,8 +14,10 @@ * @author Diego Pino Navarro https://github.com/diegopino */ -use Drupal\Core\Database\IntegrityConstraintViolationException; use Drupal\Core\Entity\EntityInterface; +use Drupal\islandora\ContextProvider\NodeContextProvider; +use Drupal\islandora\ContextProvider\MediaContextProvider; +use Drupal\islandora\ContextProvider\FileContextProvider; use Drupal\Core\Routing\RouteMatchInterface; /** @@ -82,39 +84,102 @@ function islandora_rdf_namespaces() { } /** - * Implements hook_ENTITY_TYPE_insert(). + * Implements hook_entity_insert(). */ -function islandora_node_insert(EntityInterface $entity) { - // Creates a record in the db to track the number of changes to the entity. - $versionCounter = \Drupal::service('islandora.versioncounter'); - try { - $versionCounter->create($entity->uuid()); +function islandora_entity_insert(EntityInterface $entity) { + switch ($entity->getEntityType()->id()) { + case "node": + $provider = new NodeContextProvider($entity); + break; + + case "media": + $provider = new MediaContextProvider($entity); + break; + + case "file": + $provider = new FileContextProvider($entity); + break; + + default: + $provider = NULL; + break; } - catch (IntegrityConstraintViolationException $e) { - \Drupal::logger('islandora')->error( - 'Attempted to create duplicate entry for @uuid in version counter ' . - 'table. This should never happen.', - ['@uuid' => $entity->uuid()] - ); + + if ($provider) { + $context_manager = \Drupal::service('context.manager'); + $provided = $provider->getRuntimeContexts([]); + $context_manager->evaluateContexts($provided); + + foreach ($context_manager->getActiveReactions('index') as $reaction) { + $reaction->execute($entity); + } } } /** - * Implements hook_ENTITY_TYPE_update(). + * Implements hook_entity_update(). */ -function islandora_node_update(EntityInterface $entity) { - // Increments the number of changes to the entity. - $versionCounter = \Drupal::service('islandora.versioncounter'); - $versionCounter->increment($entity->uuid()); +function islandora_entity_update(EntityInterface $entity) { + switch ($entity->getEntityType()->id()) { + case "node": + $provider = new NodeContextProvider($entity); + break; + + case "media": + $provider = new MediaContextProvider($entity); + break; + + case "file": + $provider = new FileContextProvider($entity); + break; + + default: + $provider = NULL; + break; + } + + if ($provider) { + $context_manager = \Drupal::service('context.manager'); + $provided = $provider->getRuntimeContexts([]); + $context_manager->evaluateContexts($provided); + + foreach ($context_manager->getActiveReactions('index') as $reaction) { + $reaction->execute($entity); + } + } } /** - * Implements hook_ENTITY_TYPE_update(). + * Implements hook_entity_delete(). */ -function islandora_node_delete(EntityInterface $entity) { - // Deletes the record in the db to track the number of changes to the entity. - $versionCounter = \Drupal::service('islandora.versioncounter'); - $versionCounter->delete($entity->uuid()); +function islandora_entity_delete(EntityInterface $entity) { + switch ($entity->getEntityType()->id()) { + case "node": + $provider = new NodeContextProvider($entity); + break; + + case "media": + $provider = new MediaContextProvider($entity); + break; + + case "file": + $provider = new FileContextProvider($entity); + break; + + default: + $provider = NULL; + break; + } + + if ($provider) { + $context_manager = \Drupal::service('context.manager'); + $provided = $provider->getRuntimeContexts([]); + $context_manager->evaluateContexts($provided); + + foreach ($context_manager->getActiveReactions('delete') as $reaction) { + $reaction->execute($entity); + } + } } /** diff --git a/islandora.services.yml b/islandora.services.yml index ccd4dd89a..89b115a1e 100644 --- a/islandora.services.yml +++ b/islandora.services.yml @@ -24,3 +24,13 @@ services: logger.channel.islandora: parent: logger.channel_base arguments: ['islandora'] + islandora.media_route_context_provider: + class: Drupal\islandora\ContextProvider\MediaRouteContextProvider + arguments: ['@current_route_match'] + tags: + - { name: 'context_provider' } + islandora.file_route_context_provider: + class: Drupal\islandora\ContextProvider\FileRouteContextProvider + arguments: ['@current_route_match'] + tags: + - { name: 'context_provider' } diff --git a/src/ContextProvider/FileContextProvider.php b/src/ContextProvider/FileContextProvider.php new file mode 100644 index 000000000..9b6e5cc11 --- /dev/null +++ b/src/ContextProvider/FileContextProvider.php @@ -0,0 +1,52 @@ +file = $file; + } + + /** + * {@inheritdoc} + */ + public function getRuntimeContexts(array $unqualified_context_ids) { + $context_definition = new ContextDefinition('entity:file', NULL, FALSE); + $context = new Context($context_definition, $this->file); + return ['@islandora.file_route_context_provider:file' => $context]; + } + + /** + * {@inheritdoc} + */ + public function getAvailableContexts() { + $context = new Context(new ContextDefinition('entity:file', $this->t('File from entity hook'))); + return ['@islandora.file_route_context_provider:file' => $context]; + } + +} diff --git a/src/ContextProvider/FileRouteContextProvider.php b/src/ContextProvider/FileRouteContextProvider.php new file mode 100644 index 000000000..bd55644f7 --- /dev/null +++ b/src/ContextProvider/FileRouteContextProvider.php @@ -0,0 +1,71 @@ +routeMatch = $route_match; + } + + /** + * {@inheritdoc} + */ + public function getRuntimeContexts(array $unqualified_context_ids) { + $context_definition = new ContextDefinition('entity:file', NULL, FALSE); + $value = NULL; + + // Hack the file out of the route. + $route_object = $this->routeMatch->getRouteObject(); + if ($route_object) { + $route_contexts = $route_object->getOption('parameters'); + if ($route_contexts && isset($route_contexts['file'])) { + $file = $this->routeMatch->getParameter('file'); + if ($file) { + $value = $file; + } + } + } + + $cacheability = new CacheableMetadata(); + $cacheability->setCacheContexts(['route']); + + $context = new Context($context_definition, $value); + $context->addCacheableDependency($cacheability); + return ['file' => $context]; + } + + /** + * {@inheritdoc} + */ + public function getAvailableContexts() { + $context = new Context(new ContextDefinition('entity:file', $this->t('File from URL'))); + return ['file' => $context]; + } + +} diff --git a/src/ContextProvider/MediaContextProvider.php b/src/ContextProvider/MediaContextProvider.php new file mode 100644 index 000000000..307f614ea --- /dev/null +++ b/src/ContextProvider/MediaContextProvider.php @@ -0,0 +1,52 @@ +media = $media; + } + + /** + * {@inheritdoc} + */ + public function getRuntimeContexts(array $unqualified_context_ids) { + $context_definition = new ContextDefinition('entity:media', NULL, FALSE); + $context = new Context($context_definition, $this->media); + return ['@islandora.media_route_context_provider:media' => $context]; + } + + /** + * {@inheritdoc} + */ + public function getAvailableContexts() { + $context = new Context(new ContextDefinition('entity:media', $this->t('Media from entity hook'))); + return ['@islandora.media_route_context_provider:media' => $context]; + } + +} diff --git a/src/ContextProvider/MediaRouteContextProvider.php b/src/ContextProvider/MediaRouteContextProvider.php new file mode 100644 index 000000000..a921e5632 --- /dev/null +++ b/src/ContextProvider/MediaRouteContextProvider.php @@ -0,0 +1,77 @@ +routeMatch = $route_match; + } + + /** + * {@inheritdoc} + */ + public function getRuntimeContexts(array $unqualified_context_ids) { + $result = []; + $context_definition = new ContextDefinition('entity:media', NULL, FALSE); + $value = NULL; + + // Hack the media out of the route. + $route_object = $this->routeMatch->getRouteObject(); + if ($route_object) { + $route_contexts = $route_object->getOption('parameters'); + if ($route_contexts && isset($route_contexts['media'])) { + $media = $this->routeMatch->getParameter('media'); + if ($media) { + $value = $media; + } + } + elseif ($this->routeMatch->getRouteName() == 'entity.media.add_form') { + $media_bundle = $this->routeMatch->getParameter('media_bundle'); + $value = Media::create(['bundle' => $media_bundle->id()]); + } + } + + $cacheability = new CacheableMetadata(); + $cacheability->setCacheContexts(['route']); + + $context = new Context($context_definition, $value); + $context->addCacheableDependency($cacheability); + return ['media' => $context]; + } + + /** + * {@inheritdoc} + */ + public function getAvailableContexts() { + $context = new Context(new ContextDefinition('entity:media', $this->t('Media from URL'))); + return ['media' => $context]; + } + +} diff --git a/src/ContextProvider/NodeContextProvider.php b/src/ContextProvider/NodeContextProvider.php new file mode 100644 index 000000000..637e4888b --- /dev/null +++ b/src/ContextProvider/NodeContextProvider.php @@ -0,0 +1,52 @@ +node = $node; + } + + /** + * {@inheritdoc} + */ + public function getRuntimeContexts(array $unqualified_context_ids) { + $context_definition = new ContextDefinition('entity:node', NULL, FALSE); + $context = new Context($context_definition, $this->node); + return ['@node.node_route_context:node' => $context]; + } + + /** + * {@inheritdoc} + */ + public function getAvailableContexts() { + $context = new Context(new ContextDefinition('entity:node', $this->t('Node from entity hook'))); + return ['@node.node_route_context:node' => $context]; + } + +} diff --git a/src/EventGenerator/EmitEvent.php b/src/EventGenerator/EmitEvent.php new file mode 100644 index 000000000..22037c13d --- /dev/null +++ b/src/EventGenerator/EmitEvent.php @@ -0,0 +1,220 @@ +account = $account; + $this->userStorage = $user_storage; + $this->eventGenerator = $event_generator; + $this->stomp = $stomp; + $this->auth = $auth; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('current_user'), + $container->get('entity_type.manager')->getStorage('user'), + $container->get('islandora.eventgenerator'), + $container->get('islandora.stomp'), + $container->get('jwt.authentication.jwt') + ); + } + + /** + * {@inheritdoc} + */ + public function execute($entity = NULL) { + + // Include a token for later authentication in the message. + $token = $this->auth->generateToken(); + if (empty($token)) { + // JWT isn't properly configured. Log and notify user. + \Drupal::logger('islandora')->error( + t('Error getting JWT token for message. Check JWT Configuration.') + ); + drupal_set_message( + t('Error getting JWT token for message. Check JWT Configuration.'), 'error' + ); + return; + } + + // Generate the event message. + $user = $this->userStorage->load($this->account->id()); + + if ($this->configuration['event'] == 'create') { + $message = $this->eventGenerator->generateCreateEvent($entity, $user); + } + elseif ($this->configuration['event'] == 'update') { + $message = $this->eventGenerator->generateUpdateEvent($entity, $user); + } + elseif ($this->configuration['event'] == 'delete') { + $message = $this->eventGenerator->generateDeleteEvent($entity, $user); + } + + // Transform message from string into a proper message object. + $message = new Message($message, ['Authorization' => "Bearer $token"]); + + // Send the message. + try { + $this->stomp->begin(); + $this->stomp->send($this->configuration['queue'], $message); + $this->stomp->commit(); + } + catch (StompException $e) { + // Log it. + \Drupal::logger('islandora')->error( + 'Error publishing message: @msg', + ['@msg' => $e->getMessage()] + ); + + // Notify user. + drupal_set_message( + t('Error publishing message: @msg', + ['@msg' => $e->getMessage()] + ), + 'error' + ); + } + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return [ + 'queue' => '', + 'event' => 'create', + ]; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form['queue'] = [ + '#type' => 'textfield', + '#title' => t('Queue'), + '#default_value' => $this->configuration['queue'], + '#required' => TRUE, + '#rows' => '8', + '#description' => t('Name of queue to which event is published'), + ]; + $form['event'] = [ + '#type' => 'select', + '#title' => t('Event type'), + '#default_value' => $this->configuration['event'], + '#description' => t('Type of event to emit'), + '#options' => [ + 'create' => t('Create'), + 'update' => t('Update'), + 'delete' => t('Delete'), + ], + ]; + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $this->configuration['queue'] = $form_state->getValue('queue'); + $this->configuration['event'] = $form_state->getValue('event'); + } + + /** + * {@inheritdoc} + */ + public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { + $result = AccessResult::allowed(); + return $return_as_object ? $result : $result->isAllowed(); + } + +} diff --git a/src/EventGenerator/EventGeneratorActionBase.php b/src/EventGenerator/EventGeneratorActionBase.php deleted file mode 100644 index 6c66fb061..000000000 --- a/src/EventGenerator/EventGeneratorActionBase.php +++ /dev/null @@ -1,50 +0,0 @@ -eventGenerator = $event_generator; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('islandora.eventgenerator') - ); - } - -} diff --git a/src/Form/IslandoraSettingsForm.php b/src/Form/IslandoraSettingsForm.php index db33fce87..ebfad39b2 100644 --- a/src/Form/IslandoraSettingsForm.php +++ b/src/Form/IslandoraSettingsForm.php @@ -15,8 +15,6 @@ class IslandoraSettingsForm extends ConfigFormBase { const CONFIG_NAME = 'islandora.settings'; const BROKER_URL = 'broker_url'; - const FEDORA_REST_ENDPOINT = 'fedora_rest_endpoint'; - const BROADCAST_QUEUE = 'broadcast_queue'; /** * {@inheritdoc} @@ -46,19 +44,6 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#default_value' => $config->get(self::BROKER_URL), ]; - $form[self::BROADCAST_QUEUE] = [ - '#type' => 'textfield', - '#title' => $this->t('Broadcast Queue'), - '#default_value' => $config->get(self::BROADCAST_QUEUE), - ]; - - $form[self::FEDORA_REST_ENDPOINT] = [ - '#type' => 'textfield', - '#title' => $this->t('Fedora REST Endpoint'), - '#description' => $this->t('The URL for your Fedora instance.'), - '#default_value' => $config->get(self::FEDORA_REST_ENDPOINT), - ]; - return parent::buildForm($form, $form_state); } @@ -99,8 +84,6 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $config ->set(self::BROKER_URL, $form_state->getValue(self::BROKER_URL)) - ->set(self::BROADCAST_QUEUE, $form_state->getValue(self::BROADCAST_QUEUE)) - ->set(self::FEDORA_REST_ENDPOINT, $form_state->getValue(self::FEDORA_REST_ENDPOINT)) ->save(); parent::submitForm($form, $form_state); diff --git a/src/IslandoraContextManager.php b/src/IslandoraContextManager.php new file mode 100644 index 000000000..801e3253e --- /dev/null +++ b/src/IslandoraContextManager.php @@ -0,0 +1,99 @@ +activeContexts = []; + + /** @var \Drupal\context\ContextInterface $context */ + foreach ($this->getContexts() as $context) { + if ($this->evaluateContextConditions($context, $provided) && !$context->disabled()) { + $this->activeContexts[$context->id()] = $context; + } + } + + $this->contextConditionsEvaluated = TRUE; + } + + /** + * Evaluate a contexts conditions. + * + * @param \Drupal\context\ContextInterface $context + * The context to evaluate conditions for. + * @param \Drupal\Core\Plugin\Context\Context[] $provided + * Additional provided (core) contexts to apply to Conditions. + * + * @return bool + * TRUE if conditions pass + */ + public function evaluateContextConditions(ContextInterface $context, array $provided = []) { + $conditions = $context->getConditions(); + + // Apply context to any context aware conditions. + $this->applyContexts($conditions, $provided); + + // Set the logic to use when validating the conditions. + $logic = $context->requiresAllConditions() + ? 'and' + : 'or'; + + // Of there are no conditions then the context will be + // applied as a site wide context. + if (!count($conditions)) { + $logic = 'and'; + } + + return $this->resolveConditions($conditions, $logic); + } + + /** + * Apply context to all the context aware conditions in the collection. + * + * @param \Drupal\Core\Condition\ConditionPluginCollection $conditions + * A collection of conditions to apply context to. + * @param \Drupal\Core\Plugin\Context\Context[] $provided + * Additional provided (core) contexts to apply to Conditions. + * + * @return bool + * TRUE if conditions pass + */ + protected function applyContexts(ConditionPluginCollection &$conditions, array $provided = []) { + foreach ($conditions as $condition) { + if ($condition instanceof ContextAwarePluginInterface) { + try { + if (empty($provided)) { + $contexts = $this->contextRepository->getRuntimeContexts(array_values($condition->getContextMapping())); + } + else { + $contexts = $provided; + } + $this->contextHandler->applyContextMapping($condition, $contexts); + } + catch (ContextException $e) { + return FALSE; + } + } + } + + return TRUE; + } + +} diff --git a/src/IslandoraServiceProvider.php b/src/IslandoraServiceProvider.php new file mode 100644 index 000000000..9bee8c433 --- /dev/null +++ b/src/IslandoraServiceProvider.php @@ -0,0 +1,21 @@ +getDefinition('context.manager'); + $definition->setClass('Drupal\islandora\IslandoraContextManager'); + } + +} diff --git a/src/Plugin/Action/EmitFileEvent.php b/src/Plugin/Action/EmitFileEvent.php new file mode 100644 index 000000000..105863a54 --- /dev/null +++ b/src/Plugin/Action/EmitFileEvent.php @@ -0,0 +1,16 @@ +t('The entity is a File'); + } + + /** + * {@inheritdoc} + */ + public function evaluate() { + return $this->getContextValue('file') instanceof FileInterface; + } + +} diff --git a/src/Plugin/Condition/IsMedia.php b/src/Plugin/Condition/IsMedia.php new file mode 100644 index 000000000..0ec0cf67b --- /dev/null +++ b/src/Plugin/Condition/IsMedia.php @@ -0,0 +1,35 @@ +t('The entity is a Media'); + } + + /** + * {@inheritdoc} + */ + public function evaluate() { + return $this->getContextValue('media') instanceof MediaInterface; + } + +} diff --git a/src/Plugin/Condition/IsNode.php b/src/Plugin/Condition/IsNode.php new file mode 100644 index 000000000..c7b451317 --- /dev/null +++ b/src/Plugin/Condition/IsNode.php @@ -0,0 +1,35 @@ +t('The entity is a Node'); + } + + /** + * {@inheritdoc} + */ + public function evaluate() { + return $this->getContextValue('node') instanceof NodeInterface; + } + +} diff --git a/src/Plugin/ContextReaction/DeleteReaction.php b/src/Plugin/ContextReaction/DeleteReaction.php new file mode 100644 index 000000000..88d7ff567 --- /dev/null +++ b/src/Plugin/ContextReaction/DeleteReaction.php @@ -0,0 +1,15 @@ +broadcastQueue = $broadcast_queue; - $this->stomp = $stomp; - $this->auth = $auth; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - $config = $container->get('config.factory'); - $settings = $config->get(IslandoraSettingsForm::CONFIG_NAME); - $broadcastQueue = $settings->get(IslandoraSettingsForm::BROADCAST_QUEUE); - - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $broadcastQueue, - $container->get('islandora.stomp'), - $container->get('jwt.authentication.jwt') - ); - } - - /** - * Sends a message to a broadcaster to get distributed. - * - * @param string $message - * Message body to send. - * @param array $recipients - * List of queues/topics to broadcast message to. - */ - protected function doExecute($message, array $recipients) { - // Transform recipients array into comma searated list. - $recipients = array_map('trim', $recipients); - $recipients = implode(',', $recipients); - $headers = ['IslandoraBroadcastRecipients' => $recipients]; - - // Include a token for later authentication in the message. - $token = $this->auth->generateToken(); - if (empty($token)) { - // JWT isn't properly configured. Log and notify user. - \Drupal::logger('islandora')->error( - 'Error getting JWT token for message: @msg', ['@msg' => $message] - ); - drupal_set_message( - t('Error getting JWT token for message. Check JWT Configuration.'), 'error' - ); - return; - } - - $headers['Authorization'] = "Bearer $token"; - - // Transform message from string into a proper message object. - $message = new Message($message, $headers); - - // Send the message. - try { - $this->stomp->begin(); - $this->stomp->send($this->broadcastQueue, $message); - $this->stomp->commit(); - } - catch (StompException $e) { - // Log it. - \Drupal::logger('islandora')->error( - 'Error publishing message: @msg', - ['@msg' => $e->getMessage()] - ); - - // Notify user. - drupal_set_message( - t('Error publishing message: @msg', - ['@msg' => $e->getMessage()] - ), - 'error' - ); - } - } - -} diff --git a/src/Plugin/RulesAction/CreateEventGenerator.php b/src/Plugin/RulesAction/CreateEventGenerator.php deleted file mode 100644 index e60b35869..000000000 --- a/src/Plugin/RulesAction/CreateEventGenerator.php +++ /dev/null @@ -1,42 +0,0 @@ -setProvidedValue('event_message', $this->eventGenerator->generateCreateEvent($entity, $user)); - } - -} diff --git a/src/Plugin/RulesAction/DeleteEventGenerator.php b/src/Plugin/RulesAction/DeleteEventGenerator.php deleted file mode 100644 index 4f2c3b178..000000000 --- a/src/Plugin/RulesAction/DeleteEventGenerator.php +++ /dev/null @@ -1,42 +0,0 @@ -setProvidedValue('event_message', $this->eventGenerator->generateDeleteEvent($entity, $user)); - } - -} diff --git a/src/Plugin/RulesAction/UpdateEventGenerator.php b/src/Plugin/RulesAction/UpdateEventGenerator.php deleted file mode 100644 index f01c8b8e0..000000000 --- a/src/Plugin/RulesAction/UpdateEventGenerator.php +++ /dev/null @@ -1,42 +0,0 @@ -setProvidedValue('event_message', $this->eventGenerator->generateUpdateEvent($entity, $user)); - } - -} diff --git a/src/PresetReaction/PresetReaction.php b/src/PresetReaction/PresetReaction.php new file mode 100644 index 000000000..0584b997d --- /dev/null +++ b/src/PresetReaction/PresetReaction.php @@ -0,0 +1,88 @@ +actionStorage = $action_storage; + } + + /** + * {@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')->getStorage('action') + ); + } + + /** + * {@inheritdoc} + */ + public function summary() { + return $this->t('Perform a pre-configured action.'); + } + + /** + * {@inheritdoc} + */ + public function execute(EntityInterface $entity = NULL) { + $config = $this->getConfiguration(); + $action_ids = $config['actions']; + foreach ($action_ids as $action_id) { + $action = $this->actionStorage->load($action_id); + $action->execute([$entity]); + } + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $actions = $this->actionStorage->loadMultiple(); + foreach ($actions as $action) { + $options[ucfirst($action->getType())][$action->id()] = $action->label(); + } + $config = $this->getConfiguration(); + + $form['actions'] = [ + '#title' => $this->t('Actions'), + '#description' => $this->t('Pre-configured actions to execute. Multiple actions may be selected by shift or ctrl clicking.'), + '#type' => 'select', + '#multiple' => TRUE, + '#options' => $options, + '#default_value' => isset($config['actions']) ? $config['actions'] : '', + '#size' => 15, + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $this->setConfiguration(['actions' => $form_state->getValue('actions')]); + } + +} diff --git a/src/Tests/Web/IslandoraWebTestBase.php b/src/Tests/Web/IslandoraWebTestBase.php index 25ce79bb8..dafd2f99c 100644 --- a/src/Tests/Web/IslandoraWebTestBase.php +++ b/src/Tests/Web/IslandoraWebTestBase.php @@ -26,8 +26,9 @@ abstract class IslandoraWebTestBase extends WebTestBase { 'serialization', 'rest', 'rdf', - 'typed_data', - 'rules', + 'action', + 'context', + 'context_ui', 'jsonld', 'views', 'key', diff --git a/src/VersionCounter/VersionCounter.php b/src/VersionCounter/VersionCounter.php index ffaba1391..b3df58848 100644 --- a/src/VersionCounter/VersionCounter.php +++ b/src/VersionCounter/VersionCounter.php @@ -33,9 +33,11 @@ public function __construct(Connection $database) { */ public function create($uuid) { $this->database->insert('islandora_version_count') - ->fields([ - 'uuid' => $uuid, - ]) + ->fields( + [ + 'uuid' => $uuid, + ] + ) ->execute(); } diff --git a/tests/src/Functional/EmitNodeEventTest.php b/tests/src/Functional/EmitNodeEventTest.php new file mode 100644 index 000000000..06aef6c6c --- /dev/null +++ b/tests/src/Functional/EmitNodeEventTest.php @@ -0,0 +1,508 @@ +container->get('entity_type.manager')->getStorage('key')->create([ + 'id' => 'test', + 'label' => 'Test', + 'key_type' => 'jwt_rs', + 'key_type_settings' => [ + 'algorithm' => 'RS256', + ], + 'key_provider' => 'config', + 'key_provider_settings' => [ + 'key_value' => $key_value, + ], + ]); + $key->save(); + + $jwt_config = $this->container->get('config.factory')->getEditable('jwt.config'); + $jwt_config->set('algorithm', 'RS256'); + $jwt_config->set('key_id', 'test'); + $jwt_config->save(TRUE); + } + + /** + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateCreateEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsNode::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testNodeCreateEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'bypass node access', + 'administer contexts', + 'administer actions', + ]); + $this->drupalLogin($account); + + // Create an action to emit a node event. + $action_id = $this->createEmitAction('node', 'create'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_node'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new node, which publishes the create event. + $this->postNodeAddForm('test_type', ['title[0][value]' => 'Test Node'], 'Save'); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Create'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\MediaContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\MediaContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateCreateEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsMedia::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testMediaCreateEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'administer contexts', + 'administer actions', + 'view media', + 'create media', + ]); + $this->drupalLogin($account); + + // Create an action to emit a media event. + $action_id = $this->createEmitAction('media', 'create'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_media'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new media, which publishes the create event. + $this->createThumbnailWithFile(); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Create'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\FileContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\FileContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateCreateEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsFile::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testFileCreateEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'administer contexts', + 'administer actions', + 'view media', + 'create media', + ]); + $this->drupalLogin($account); + + // Create an action to emit a media event. + $action_id = $this->createEmitAction('file', 'create'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_file'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new file, which publishes the create event. + $this->createThumbnailWithFile(); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Create'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateUpdateEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsNode::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testNodeUpdateEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'bypass node access', + 'administer contexts', + 'administer actions', + ]); + $this->drupalLogin($account); + + // Create an action to emit a node event. + $action_id = $this->createEmitAction('node', 'update'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_node'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new node, which publishes the update event. + $this->postNodeAddForm('test_type', ['title[0][value]' => 'Test Node'], 'Save'); + + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Update'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\MediaContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\MediaContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateUpdateEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsMedia::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testMediaUpdateEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'administer contexts', + 'administer actions', + 'view media', + 'create media', + ]); + $this->drupalLogin($account); + + // Create an action to emit a media event. + $action_id = $this->createEmitAction('media', 'update'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_media'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new media, which publishes the update event. + $this->createThumbnailWithFile(); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Update'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\FileContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\FileContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateUpdateEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsFile::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testFileUpdateEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'administer contexts', + 'administer actions', + 'view media', + 'create media', + ]); + $this->drupalLogin($account); + + // Create an action to emit a media event. + $action_id = $this->createEmitAction('file', 'update'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_file'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new file, which publishes the update event. + $this->createThumbnailWithFile(); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Update'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateDeleteEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsNode::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testNodeDeleteEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'bypass node access', + 'administer contexts', + 'administer actions', + ]); + $this->drupalLogin($account); + + // Create an action to emit a node event. + $action_id = $this->createEmitAction('node', 'delete'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_node'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new node, which publishes the delete event (lol). + $this->postNodeAddForm('test_type', ['title[0][value]' => 'Test Node'], 'Save'); + + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Delete'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\MediaContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\MediaContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateDeleteEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsMedia::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testMediaDeleteEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'administer contexts', + 'administer actions', + 'view media', + 'create media', + ]); + $this->drupalLogin($account); + + // Create an action to emit a media event. + $action_id = $this->createEmitAction('media', 'delete'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_media'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new media, which publishes the delete event. + $this->createThumbnailWithFile(); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Delete'); + } + + /** + * @covers \Drupal\islandora\ContextProvider\FileContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\FileContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\EventGenerator\EmitEvent::buildConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::submitConfigurationForm + * @covers \Drupal\islandora\EventGenerator\EmitEvent::execute + * @covers \Drupal\islandora\EventGenerator\EventGenerator::generateDeleteEvent + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\Plugin\Condition\IsFile::evaluate + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testFileDeleteEvent() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'administer contexts', + 'administer actions', + 'view media', + 'create media', + ]); + $this->drupalLogin($account); + + // Create an action to emit a media event. + $action_id = $this->createEmitAction('file', 'delete'); + + // Create a context and add the action as an index reaction. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_file'); + $this->addPresetReaction('test', 'index', $action_id); + $this->assertSession()->statusCodeEquals(200); + + // Create a new file, which publishes the delete event. + $this->createThumbnailWithFile(); + + // Validate the message actually gets sent. + $queue = str_replace('_', '-', $action_id); + $this->verifyMessageIsSent($queue, 'Delete'); + } + + /** + * Utility function to create an emit action. + * + * @param string $entity_type + * Entity type id. + * @param string $event_type + * Event type (create, update, or delete). + */ + protected function createEmitAction($entity_type, $event_type) { + $this->drupalGet('admin/config/system/actions'); + $this->getSession()->getPage()->findById("edit-action")->selectOption("Emit a $entity_type event to a queue/topic..."); + $this->getSession()->getPage()->pressButton(t('Create')); + $this->assertSession()->statusCodeEquals(200); + + $action_id = "emit_" . $entity_type . "_" . $event_type; + $this->getSession()->getPage()->fillField('edit-label', "Emit $entity_type $event_type"); + $this->getSession()->getPage()->fillField('edit-id', $action_id); + $this->getSession()->getPage()->fillField('edit-queue', "emit-$entity_type-$event_type"); + $this->getSession()->getPage()->findById("edit-event")->selectOption($event_type); + $this->getSession()->getPage()->pressButton(t('Save')); + $this->assertSession()->statusCodeEquals(200); + + return $action_id; + } + + /** + * Asserts the message was delivered and checks its general shape. + * + * @param string $queue + * The queue to check for the message. + * @param string $event_type + * Event type (create, update, or delete). + */ + protected function verifyMessageIsSent($queue, $event_type) { + // Verify message is sent. + $stomp = $this->container->get('islandora.stomp'); + try { + $stomp->subscribe($queue); + while ($msg = $stomp->read()) { + $headers = $msg->getHeaders(); + $this->assertTrue( + isset($headers['Authorization']), + "Authorization header must be set" + ); + $matches = []; + $this->assertTrue( + preg_match('/^Bearer (.*)/', $headers['Authorization'], $matches), + "Authorization header must be a bearer token" + ); + $this->assertTrue( + count($matches) == 2 && !empty($matches[1]), + "Bearer token must not be empty" + ); + + $body = $msg->getBody(); + $body = json_decode($body, TRUE); + $type = $body['type']; + $this->assertTrue($type == $event_type, "Expected $event_type, received $type"); + } + $stomp->unsubscribe(); + } + catch (StompException $e) { + $this->assertTrue(FALSE, "There was an error connecting to the stomp broker"); + } + } + +} diff --git a/tests/src/Functional/IndexingTest.php b/tests/src/Functional/IndexingTest.php new file mode 100644 index 000000000..bd451fc38 --- /dev/null +++ b/tests/src/Functional/IndexingTest.php @@ -0,0 +1,75 @@ +container->get('entity_type.manager')->getStorage('action')->create([ + 'id' => 'goodbye_world', + 'label' => 'Goodbye World', + 'type' => 'system', + 'plugin' => 'action_message_action', + 'configuration' => [ + 'message' => 'Goodbye, Cruel World!', + ], + ]); + $goodbye_world->save(); + } + + /** + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::__construct + * @covers \Drupal\islandora\ContextProvider\NodeContextProvider::getRuntimeContexts + * @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts + * @covers \Drupal\islandora\IslandoraContextManager::applyContexts + * @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm + * @covers \Drupal\islandora\PresetReaction\PresetReaction::execute + * @covers \Drupal\islandora\IslandoraServiceProvider::alter + */ + public function testIndexing() { + // Create a test user. + $account = $this->drupalCreateUser([ + 'bypass node access', + 'administer contexts', + 'administer actions', + ]); + $this->drupalLogin($account); + + $this->createContext('Test', 'test'); + $this->addPresetReaction('test', 'index', 'hello_world'); + + // Create a new node and confirm Hello World! is printed to the screen. + $this->postNodeAddForm('test_type', ['title[0][value]' => 'Test Node'], 'Save'); + $this->assertSession()->pageTextContains("Hello World!"); + + // Stash the node's url. + $url = $this->getUrl(); + + // Edit the node and confirm Hello World! is printed to the screen. + $this->postEntityEditForm($url, ['title[0][value]' => 'Test Node Changed'], 'Save'); + $this->assertSession()->pageTextContains("Hello World!"); + + // Add the Goodbye World reaction. + $this->addPresetReaction('test', 'delete', 'goodbye_world'); + + // Delete the node. + $this->drupalPostForm("$url/delete", [], t('Delete')); + $this->assertSession()->statusCodeEquals(200); + + // Confirm Goodbye, Cruel World! is printed to the screen. + $this->assertSession()->pageTextContains("Goodbye, Cruel World!"); + } + +} diff --git a/tests/src/Functional/IsFileTest.php b/tests/src/Functional/IsFileTest.php new file mode 100644 index 000000000..df8997e31 --- /dev/null +++ b/tests/src/Functional/IsFileTest.php @@ -0,0 +1,58 @@ +drupalCreateUser([ + 'administer contexts', + 'view media', + 'create media', + 'update media', + ]); + $this->drupalLogin($account); + + // Set it up. + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_file'); + $this->addPresetReaction('test', 'index', 'hello_world'); + + // Add a new Thumbnail media and confirm Hello World! is printed to the + // screen for the file upload. + $this->createThumbnailWithFile(); + $this->assertSession()->pageTextContains("Hello World!"); + + // Stash the media's url. + $url = $this->getUrl(); + + // Edit the media, not touching the file this time. + $values = [ + 'name[0][value]' => 'Test Media Changed', + ]; + $this->postEntityEditForm($url, $values, 'Save and keep published'); + + // Confirm Hello World! is not printed to the screen. + $this->assertSession()->pageTextNotContains("Hello World!"); + } + +} diff --git a/tests/src/Functional/IsMediaTest.php b/tests/src/Functional/IsMediaTest.php new file mode 100644 index 000000000..967b94608 --- /dev/null +++ b/tests/src/Functional/IsMediaTest.php @@ -0,0 +1,52 @@ +drupalCreateUser([ + 'bypass node access', + 'administer contexts', + 'view media', + 'create media', + 'update media', + ]); + $this->drupalLogin($account); + + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_media'); + $this->addPresetReaction('test', 'index', 'hello_world'); + + // Add a new Thumbnail media and confirm Hello World! is printed to the + // screen. + $this->createThumbnailWithFile(); + $this->assertSession()->pageTextContains("Hello World!"); + + // Create a new node. + $this->postNodeAddForm('test_type', ['title[0][value]' => 'Test Node'], 'Save'); + + // Confirm Hello World! is not printed to the screen. + $this->assertSession()->pageTextNotContains("Hello World!"); + } + +} diff --git a/tests/src/Functional/IsNodeTest.php b/tests/src/Functional/IsNodeTest.php new file mode 100644 index 000000000..1c4b7c144 --- /dev/null +++ b/tests/src/Functional/IsNodeTest.php @@ -0,0 +1,50 @@ +drupalCreateUser([ + 'bypass node access', + 'administer contexts', + 'view media', + 'create media', + 'update media', + ]); + $this->drupalLogin($account); + + $this->createContext('Test', 'test'); + $this->addCondition('test', 'is_node'); + $this->addPresetReaction('test', 'index', 'hello_world'); + + // Create a new node confirm Hello World! is printed to the screen. + $this->postNodeAddForm('test_type', ['title[0][value]' => 'Test Node'], 'Save'); + $this->assertSession()->pageTextContains("Hello World!"); + + // Add a new Thumbnail media and confirm Hello World! is not printed to the + // screen. + $this->createThumbnailWithFile(); + $this->assertSession()->pageTextNotContains("Hello World!"); + } + +} diff --git a/tests/src/Functional/IslandoraFunctionalTestBase.php b/tests/src/Functional/IslandoraFunctionalTestBase.php new file mode 100644 index 000000000..845a21d6c --- /dev/null +++ b/tests/src/Functional/IslandoraFunctionalTestBase.php @@ -0,0 +1,123 @@ +container->get('entity_type.manager')->getStorage('context')->load('node')->delete(); + $this->container->get('entity_type.manager')->getStorage('context')->load('media')->delete(); + $this->container->get('entity_type.manager')->getStorage('context')->load('file')->delete(); + + // Create a test content type. + $test_type = $this->container->get('entity_type.manager')->getStorage('node_type')->create([ + 'type' => 'test_type', + 'label' => 'Test Type', + ]); + $test_type->save(); + + // Create an action that dsm's "Hello World!". + $hello_world = $this->container->get('entity_type.manager')->getStorage('action')->create([ + 'id' => 'hello_world', + 'label' => 'Hello World', + 'type' => 'system', + 'plugin' => 'action_message_action', + 'configuration' => [ + 'message' => 'Hello World!', + ], + ]); + $hello_world->save(); + + } + + /** + * Creates a test context. + */ + protected function createContext($label, $name) { + $this->drupalPostForm('admin/structure/context/add', ['label' => $label, 'name' => $name], t('Save')); + $this->assertSession()->statusCodeEquals(200); + } + + /** + * Adds a condition to the test context. + */ + protected function addCondition($context_id, $condition_id) { + $this->drupalGet("admin/structure/context/$context_id/condition/add/$condition_id"); + $this->getSession()->getPage()->pressButton('Save and continue'); + $this->assertSession()->statusCodeEquals(200); + } + + /** + * Adds a reaction to the test context. + */ + protected function addPresetReaction($context_id, $reaction_type, $action_id) { + $this->drupalGet("admin/structure/context/$context_id/reaction/add/$reaction_type"); + $this->getSession()->getPage()->findById("edit-reactions-$reaction_type-actions")->selectOption($action_id); + $this->getSession()->getPage()->pressButton(t('Save and continue')); + $this->assertSession()->statusCodeEquals(200); + } + + /** + * Creates a new TN media with a file. + */ + protected function createThumbnailWithFile() { + // Have to do this in two steps since there's no ajax for the alt text. + // It's as annoying as in real life. + $file = current($this->getTestFiles('image')); + $values = [ + 'name[0][value]' => 'Test Media', + 'files[field_image_0]' => drupal_realpath($file->uri), + ]; + $this->drupalPostForm('media/add/tn', $values, t('Save and publish')); + $values = [ + 'field_image[0][alt]' => 'Alternate text', + ]; + $this->getSession()->getPage()->fillField('edit-field-image-0-alt', 'alt text'); + $this->getSession()->getPage()->pressButton(t('Save and publish')); + $this->assertResponse(200); + } + + /** + * Create a new node by posting its add form. + */ + protected function postNodeAddForm($bundle_id, $values, $button_text) { + $this->drupalPostForm("node/add/$bundle_id", $values, t('@text', ['@text' => $button_text])); + $this->assertResponse(200); + } + + /** + * Edits a node by posting its edit form. + */ + protected function postEntityEditForm($entity_url, $values, $button_text) { + $this->drupalPostForm("$entity_url/edit", $values, t('@text', ['@text' => $button_text])); + $this->assertResponse(200); + } + +} diff --git a/tests/src/Kernel/BroadcasterTest.php b/tests/src/Kernel/BroadcasterTest.php deleted file mode 100644 index 87bfaec7d..000000000 --- a/tests/src/Kernel/BroadcasterTest.php +++ /dev/null @@ -1,138 +0,0 @@ -prophesize(StatefulStomp::CLASS); - $prophecy->begin()->willThrow(new StompException('STOMP EXCEPTION')); - $stomp = $prophecy->reveal(); - - $action = $this->createBroadcaster($stomp); - - try { - // Execute the action. - $action->execute(); - $this->assertTrue(TRUE, "The execute() method must squash StompExceptions."); - } - catch (\Exception $e) { - $this->assertTrue(FALSE, "The execute() method must squash StompExceptions."); - } - - } - - /** - * Tests that the action DOES NOT squash any other Exception. - * - * @covers \Drupal\islandora\Plugin\RulesAction\Broadcaster::execute - * @expectedException \Exception - */ - public function testExecuteDoesNotSquashOtherExceptions() { - // Set up a fake Stomp client to throw a non-StompException when used. - $prophecy = $this->prophesize(StatefulStomp::CLASS); - $prophecy->begin()->willThrow(new \Exception('NOT A STOMP EXCEPTION')); - $stomp = $prophecy->reveal(); - - $action = $this->createBroadcaster($stomp); - - // This should throw an exception. - $action->execute(); - } - - /** - * Tests that the action publishes the message to be broadcast to a broker. - * - * @covers \Drupal\islandora\Plugin\RulesAction\Broadcaster::execute - */ - public function testBrokerIntegration() { - // Grab a legit stomp client, using values from config. - $this->installConfig('islandora'); - $stomp = $this->container->get('islandora.stomp'); - - // Create and execute the action. - $action = $this->createBroadcaster($stomp); - $action->execute(); - - // Verify the message actually got sent. - try { - $stomp->subscribe($this->testQueue); - $msg = $stomp->read(); - - $this->assertTrue( - strcmp($msg->getBody(), 'test') == 0, - "Message body is not 'test'" - ); - - $headers = $msg->getHeaders(); - $this->assertTrue( - strcmp($headers['IslandoraBroadcastRecipients'], 'activemq:queue:foo,activemq:queue:bar') == 0, - "IslandoraBroadcastRecipients header must be a comma separated list of endpoints" - ); - $this->assertTrue( - strcmp($headers['Authorization'], 'Bearer some_token') == 0, - "Authorization header must be set" - ); - $stomp->unsubscribe(); - } - catch (StompException $e) { - $this->assertTrue(FALSE, "There was an error connecting to the stomp broker"); - } - } - - /** - * Utility function to create a broadcaster action from a Stomp prophecy. - * - * @param \Stomp\StatefulStomp $stomp - * Stomp instance or prophecy. - * - * @return \Drupal\islandora\Plugin\RulesAction\Broadcaster - * Broadcaster, ready to test. - */ - protected function createBroadcaster(StatefulStomp $stomp) { - // Pull the plugin definition out of the plugin system. - $actionManager = $this->container->get('plugin.manager.rules_action'); - $definitions = $actionManager->getDefinitions(); - $pluginDefinition = $definitions['islandora_broadcast']; - - // Mock a JWT generator. - $prophecy = $this->prophesize(JwtAuth::class); - $prophecy->generateToken()->willReturn("some_token"); - $jwt = $prophecy->reveal(); - - $action = new Broadcaster( - [], - 'islandora_broadcast', - $pluginDefinition, - $this->testQueue, - $stomp, - $jwt - ); - - // Set the required contexts for the action to run. - $action->setContextValue('message', "test"); - $action->setContextValue('recipients', ['activemq:queue:foo', 'activemq:queue:bar']); - - return $action; - } - -} diff --git a/tests/src/Kernel/CreateEventGeneratorTest.php b/tests/src/Kernel/CreateEventGeneratorTest.php deleted file mode 100644 index 5353b0755..000000000 --- a/tests/src/Kernel/CreateEventGeneratorTest.php +++ /dev/null @@ -1,36 +0,0 @@ -action = $this->actionManager->createInstance('islandora_create_event_generator'); - } - - /** - * Tests the CreateEventGenerator action. - * - * @covers \Drupal\islandora\Plugin\RulesAction\CreateEventGenerator::execute - */ - public function testExecute() { - // Execute the action and get the message it outputs. - $msg = $this->assertExecution(); - - // Assert it's outputs a 'Create' event. - $this->assertTrue($msg["type"] == "Create", "Event must be of type 'Create'."); - } - -} diff --git a/tests/src/Kernel/DeleteEventGeneratorTest.php b/tests/src/Kernel/DeleteEventGeneratorTest.php deleted file mode 100644 index 63c729976..000000000 --- a/tests/src/Kernel/DeleteEventGeneratorTest.php +++ /dev/null @@ -1,36 +0,0 @@ -action = $this->actionManager->createInstance('islandora_delete_event_generator'); - } - - /** - * Tests the DeleteEventGenerator action. - * - * @covers \Drupal\islandora\Plugin\RulesAction\DeleteEventGenerator::execute - */ - public function testExecute() { - // Execute the action and get the message it outputs. - $msg = $this->assertExecution(); - - // Assert it's outputs a 'Delete' event. - $this->assertTrue($msg["type"] == "Delete", "Event must be of type 'Delete'."); - } - -} diff --git a/tests/src/Kernel/EventGeneratorActionTestBase.php b/tests/src/Kernel/EventGeneratorActionTestBase.php deleted file mode 100644 index 395847232..000000000 --- a/tests/src/Kernel/EventGeneratorActionTestBase.php +++ /dev/null @@ -1,59 +0,0 @@ -actionManager = $this->container->get('plugin.manager.rules_action'); - } - - /** - * Utility function to bootstrap an action, run it, and do basic asserts. - * - * @return array - * The event message, as an array. - */ - protected function assertExecution() { - - // Set the required contexts for the action to run. - $this->action->setContextValue('entity', $this->entity); - $this->action->setContextValue('user', $this->user); - - // Execute the action. - $this->action->execute(); - - // Assert some basics. - $message_str = $this->action->getProvidedContext('event_message')->getContextValue(); - $this->assertNotEmpty($message_str, "Event message must not be empty."); - $message = json_decode($message_str, TRUE); - $this->assertTrue(array_key_exists('type', $message), "Event has type key."); - - // Return the event message. - return $message; - } - -} diff --git a/tests/src/Kernel/EventGeneratorTest.php b/tests/src/Kernel/EventGeneratorTest.php index 07d673529..46a6cb8c7 100644 --- a/tests/src/Kernel/EventGeneratorTest.php +++ b/tests/src/Kernel/EventGeneratorTest.php @@ -3,6 +3,9 @@ namespace Drupal\Tests\islandora\Kernel; use Drupal\islandora\EventGenerator\EventGenerator; +use Drupal\node\Entity\Node; +use Drupal\node\Entity\NodeType; +use Drupal\simpletest\UserCreationTrait; /** * Tests the EventGenerator default implementation. @@ -10,7 +13,9 @@ * @group islandora * @coversDefaultClass \Drupal\islandora\EventGenerator\EventGenerator */ -class EventGeneratorTest extends EventGeneratorTestBase { +class EventGeneratorTest extends IslandoraKernelTestBase { + + use UserCreationTrait; /** * The EventGenerator to test. @@ -19,12 +24,45 @@ class EventGeneratorTest extends EventGeneratorTestBase { */ protected $eventGenerator; + /** + * User entity. + * + * @var \Drupal\user\UserInterface + */ + protected $user; + + /** + * Fedora resource entity. + * + * @var \Drupal\node\Entity\NodeInterface + */ + protected $entity; + /** * {@inheritdoc} */ public function setUp() { parent::setUp(); + // Create a test user. + $this->user = $this->createUser(['administer nodes']); + + $test_type = NodeType::create([ + 'type' => 'test_type', + 'label' => 'Test Type', + ]); + $test_type->save(); + + // Create a test entity. + $this->entity = Node::create([ + "type" => "test_type", + "uid" => $this->user->get('uid'), + "title" => "Test Fixture", + "langcode" => "und", + "status" => 1, + ]); + $this->entity->save(); + // Create the event generator so we can test it. $this->eventGenerator = new EventGenerator(); } diff --git a/tests/src/Kernel/EventGeneratorTestBase.php b/tests/src/Kernel/EventGeneratorTestBase.php deleted file mode 100644 index f3ba664a5..000000000 --- a/tests/src/Kernel/EventGeneratorTestBase.php +++ /dev/null @@ -1,56 +0,0 @@ -user = $this->createUser(['administer nodes']); - - $test_type = NodeType::create([ - 'type' => 'test_type', - 'label' => 'Test Type', - ]); - $test_type->save(); - - // Create a test entity. - $this->entity = Node::create([ - "type" => "test_type", - "uid" => $this->user->get('uid'), - "title" => "Test Fixture", - "langcode" => "und", - "status" => 1, - ]); - $this->entity->save(); - } - -} diff --git a/tests/src/Kernel/IslandoraKernelTestBase.php b/tests/src/Kernel/IslandoraKernelTestBase.php index b4f5aef0f..892b0a5aa 100644 --- a/tests/src/Kernel/IslandoraKernelTestBase.php +++ b/tests/src/Kernel/IslandoraKernelTestBase.php @@ -28,8 +28,8 @@ abstract class IslandoraKernelTestBase extends KernelTestBase { 'basic_auth', 'hal', 'rdf', - 'typed_data', - 'rules', + 'action', + 'context', 'jsonld', 'views', 'key', @@ -53,8 +53,8 @@ public function setUp() { $this->installSchema('node', 'node_access'); $this->installEntitySchema('user'); $this->installEntitySchema('node'); + $this->installEntitySchema('context'); $this->installConfig('filter'); - $this->installSchema('islandora', 'islandora_version_count'); } } diff --git a/tests/src/Kernel/UpdateEventGeneratorTest.php b/tests/src/Kernel/UpdateEventGeneratorTest.php deleted file mode 100644 index 00653f521..000000000 --- a/tests/src/Kernel/UpdateEventGeneratorTest.php +++ /dev/null @@ -1,36 +0,0 @@ -action = $this->actionManager->createInstance('islandora_update_event_generator'); - } - - /** - * Tests the UpdateEventGenerator action. - * - * @covers \Drupal\islandora\Plugin\RulesAction\UpdateEventGenerator::execute - */ - public function testExecute() { - // Execute the action and get the message it outputs. - $msg = $this->assertExecution(); - - // Assert it's outputs a 'Update' event. - $this->assertTrue($msg["type"] == "Update", "Event must be of type 'Update'."); - } - -} diff --git a/tests/src/Kernel/VersionCounterTest.php b/tests/src/Kernel/VersionCounterTest.php deleted file mode 100644 index 225fc66df..000000000 --- a/tests/src/Kernel/VersionCounterTest.php +++ /dev/null @@ -1,109 +0,0 @@ -user = $this->createUser(['administer nodes']); - - $test_type = NodeType::create([ - 'type' => 'test_type', - 'label' => 'Test Type', - ]); - $test_type->save(); - - // Create a test entity. - $this->entity = Node::create([ - "type" => "test_type", - "uid" => $this->user->get('uid'), - "title" => "Test Fixture", - "langcode" => "und", - "status" => 1, - ]); - $this->entity->save(); - } - - /** - * @covers \Drupal\islandora\VersionCounter\VersionCounter::create - * @covers \Drupal\islandora\VersionCounter\VersionCounter::get - */ - public function testInitializesRecord() { - $versionCounter = $this->container->get('islandora.versioncounter'); - - $this->assertTrue($versionCounter->get($this->entity->uuid()) == 0, - "Version counter db record must be initialized to 0." - ); - } - - /** - * @covers \Drupal\islandora\VersionCounter\VersionCounter::create - * @expectedException \Drupal\Core\Database\IntegrityConstraintViolationException - */ - public function testCannotCreateDuplicateRecord() { - $versionCounter = $this->container->get('islandora.versioncounter'); - $versionCounter->create($this->entity->uuid()); - } - - /** - * @covers \Drupal\islandora\VersionCounter\VersionCounter::increment - * @covers \Drupal\islandora\VersionCounter\VersionCounter::get - */ - public function testRecordIncrementsOnUpdate() { - $this->entity->setTitle("New Title"); - $this->entity->save(); - - $versionCounter = $this->container->get('islandora.versioncounter'); - - $this->assertTrue($versionCounter->get($this->entity->uuid()) == 1, - "Version counter db record must increment on entity update." - ); - } - - /** - * @covers \Drupal\islandora\VersionCounter\VersionCounter::delete - * @covers \Drupal\islandora\VersionCounter\VersionCounter::get - */ - public function testRecordsGetCleanedUp() { - $this->entity->delete(); - - $versionCounter = $this->container->get('islandora.versioncounter'); - - $this->assertTrue($versionCounter->get($this->entity->uuid()) == -1, - "Version counter db record must be deleted on entity delete." - ); - } - -}