Skip to content

Commit bd64c03

Browse files
[#267] Add the apigee_edge_actions module (#360)
* Add the apigee_edge_actions module * Update dependencies for tests * Remove unused service provider * [#359] Fix tests that relied on username displayed as firstname lastname. * Remove UUID from config files * Move response templates to apigee_mock_api_client * Move helper methods to the ApigeeMockApiClientHelperTrait * Add comments and remove unused imports * Fix composer.json * [#267] Optimize get app from AppCredentialEventSubscriber, and developer for events. * Update README * Use early return for _apigee_edge_actions_dispatch_entity_event * Fix condition for early return * Update mock response * [#267] Revert ApigeeMockApiClientHelperTrait * [#267] Implement suggestions from code review * [#267] Add team to team app events * [#267] Update queueDeveloperAppResponse * [#267] Revert ApigeeMockApiClientHelperTrait * [#261] Fix issue with rules SystemMailToUsersOfRole action * [#267] Fix typo in README Co-authored-by: Arlina Espinoza <[email protected]>
1 parent 22c76fc commit bd64c03

File tree

47 files changed

+2937
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2937
-1
lines changed

.circleci/RoboFile.php

+3
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,9 @@ public function configureModuleDependencies()
411411
unset($config->require->{"drupal/core"});
412412
$config->require->{"drupal/core-recommended"} = "~8.8";
413413

414+
// Add rules for testing apigee_edge_actions.
415+
$config->require->{"drupal/rules"} = "^3.0@alpha";
416+
414417
// We require Drupal console and drush for some tests.
415418
$config->require->{"drupal/console"} = "~1.0";
416419
$config->require->{"drush/drush"} = "^9.7";

modules/apigee_edge_actions/README.md

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Apigee Edge Actions
2+
3+
The Apigee Edge Actions module provides rules integration for Apigee Edge. It makes it easy to automate tasks and react on events such as:
4+
5+
* Sending an email when an App is created.
6+
* Notify a developer when added to a Team.
7+
* Notify admin when an API product is added to an App.
8+
9+
## Events
10+
11+
The following events are supported out of the box:
12+
13+
### App
14+
`\Drupal\apigee_edge\Entity\DeveloperApp`
15+
16+
| Event | Name |
17+
|---|---|
18+
| After saving a new App | `apigee_edge_actions_entity_insert:developer_app` |
19+
| After deleting an App | `apigee_edge_actions_entity_delete:developer_app` |
20+
| After updating an App | `apigee_edge_actions_entity_insert:developer_app` |
21+
| After adding an API Product | `apigee_edge_actions_entity_add_product:developer_app` |
22+
| After removing an API Product | `apigee_edge_actions_entity_remove_product:developer_app` |
23+
24+
### Team App
25+
`\Drupal\apigee_edge_teams\Entity\TeamApp`
26+
27+
| Event | Name |
28+
|---|---|
29+
| After saving a new Team App | `apigee_edge_actions_entity_insert:team_app` |
30+
| After deleting an Team App | `apigee_edge_actions_entity_delete:team_app` |
31+
| After updating an Team App | `apigee_edge_actions_entity_insert:team_app` |
32+
| After adding an API Product | `apigee_edge_actions_entity_add_product:team_app` |
33+
| After removing an API Product | `apigee_edge_actions_entity_remove_product:team_app` |
34+
35+
### Team
36+
`\Drupal\apigee_edge_teams\Entity\Team`
37+
38+
| Event | Name |
39+
|---|---|
40+
| After saving a new Team | `apigee_edge_actions_entity_insert:team` |
41+
| After deleting an Team | `apigee_edge_actions_entity_delete:team` |
42+
| After updating an Team | `apigee_edge_actions_entity_insert:team` |
43+
| After adding a team member | `apigee_edge_actions_entity_add_member:team` |
44+
| After removing a team member | `apigee_edge_actions_entity_remove_member:team` |
45+
46+
## Examples
47+
48+
The `apigee_edge_actions_examples` module ships with some example rules you can use to test:
49+
50+
1. Log a message when team is deleted.
51+
2. Notify developer when added to a team
52+
3. Notify developer when adding a new app
53+
4. Notify site admins when app is created
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: Apigee Edge Actions
2+
description: Rules integration for Apigee Edge.
3+
package: Apigee (Experimental)
4+
type: module
5+
core: 8.x
6+
configure: entity.rules_reaction_rule.collection
7+
dependencies:
8+
- apigee_edge:apigee_edge
9+
- rules:rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
/**
4+
* Copyright 2020 Google Inc.
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* version 2 as published by the Free Software Foundation.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18+
* MA 02110-1301, USA.
19+
*/
20+
21+
use Drupal\apigee_edge\Entity\DeveloperAppInterface;
22+
use Drupal\apigee_edge_actions\Event\EdgeEntityEventEdge;
23+
use Drupal\apigee_edge\Entity\AppInterface;
24+
use Drupal\apigee_edge_actions\Plugin\RulesAction\SystemMailToUsersOfRole;
25+
use Drupal\Core\Entity\EntityInterface;
26+
27+
/**
28+
* Implements hook_entity_insert().
29+
*/
30+
function apigee_edge_actions_entity_insert(EntityInterface $entity) {
31+
_apigee_edge_actions_dispatch_entity_event($entity, 'insert');
32+
}
33+
34+
/**
35+
* Implements hook_entity_delete().
36+
*/
37+
function apigee_edge_actions_entity_delete(EntityInterface $entity) {
38+
_apigee_edge_actions_dispatch_entity_event($entity, 'delete');
39+
}
40+
41+
/**
42+
* Implements hook_entity_update().
43+
*/
44+
function apigee_edge_actions_entity_update(EntityInterface $entity) {
45+
_apigee_edge_actions_dispatch_entity_event($entity, 'update');
46+
}
47+
48+
/**
49+
* Implements hook_archiver_info_alter().
50+
*/
51+
function apigee_edge_actions_rules_action_info_alter(&$info) {
52+
// Override the class for this rule action to handle param upcasting.
53+
// @see https://www.drupal.org/project/rules/issues/2800749
54+
$info['rules_email_to_users_of_role']['class'] = SystemMailToUsersOfRole::class;
55+
}
56+
57+
/**
58+
* Helper to dispatch an entity event.
59+
*
60+
* @param \Drupal\Core\Entity\EntityInterface $entity
61+
* The entity.
62+
* @param string $event_name
63+
* The event name.
64+
*
65+
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
66+
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
67+
*/
68+
function _apigee_edge_actions_dispatch_entity_event(EntityInterface $entity, string $event_name) {
69+
if (!Drupal::service('apigee_edge_actions.edge_entity_type_manager')
70+
->isFieldableEdgeEntityType($entity->getEntityType())) {
71+
return;
72+
}
73+
74+
$dispatched_event_name = "apigee_edge_actions_entity_$event_name:{$entity->getEntityTypeId()}";
75+
76+
$arguments = [
77+
$entity->getEntityTypeId() => $entity
78+
];
79+
80+
// Note: Refactor this to plugins if more entity types requires custom
81+
// arguments.
82+
if ($entity instanceof AppInterface) {
83+
if ($entity instanceof DeveloperAppInterface) {
84+
// $entity->getCreatedBy() is deprecated, so to get the developer Drupal
85+
// account we need to load the developer by UUID, then load the user by
86+
// email.
87+
// Note: $entity->getAppOwner() returns a developer UUID, which is
88+
// different from a user's UUID, so we load the developer first and then
89+
// the account.
90+
$developer = Drupal::entityTypeManager()
91+
->getStorage('developer')
92+
->load($entity->getAppOwner());
93+
$user_id = $developer->getEmail();
94+
}
95+
else {
96+
/** @var \Drupal\apigee_edge_teams\Entity\TeamAppInterface $entity */
97+
// For TeamApps, getAppOwner() is a team name, not a developer or email,
98+
// and we cannot rely on getCreatedBy() as it is deprecated, so we
99+
// default to the current user for the developer.
100+
$user_id = Drupal::currentUser()->getEmail();
101+
102+
// Add the team.
103+
$team = Drupal::entityTypeManager()
104+
->getStorage('team')
105+
->load($entity->getAppOwner());
106+
$arguments['team'] = $team;
107+
}
108+
109+
// Add the developer.
110+
$arguments['developer'] = user_load_by_mail($user_id);
111+
}
112+
113+
if ($event_name === 'update') {
114+
$arguments["{$entity->getEntityTypeId()}_unchanged"] = $entity->original;
115+
}
116+
117+
/** @var \Drupal\apigee_edge\Entity\EdgeEntityInterface $entity */
118+
Drupal::service('event_dispatcher')
119+
->dispatch($dispatched_event_name, new EdgeEntityEventEdge($entity, $arguments));
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
apigee_edge_actions_entity_insert:
2+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityInsertEventDeriver'
3+
event: 'insert'
4+
5+
apigee_edge_actions_entity_delete:
6+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityDeleteEventDeriver'
7+
event: 'delete'
8+
9+
apigee_edge_actions_entity_update:
10+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityUpdateEventDeriver'
11+
event: 'update'
12+
13+
apigee_edge_actions_entity_add_member:
14+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityAddMemberEventDeriver'
15+
event: 'add_member'
16+
17+
apigee_edge_actions_entity_remove_member:
18+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityRemoveMemberEventDeriver'
19+
event: 'remove_member'
20+
21+
apigee_edge_actions_entity_add_product:
22+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityAddProductEventDeriver'
23+
event: 'add_product'
24+
25+
apigee_edge_actions_entity_remove_product:
26+
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityRemoveProductEventDeriver'
27+
event: 'remove_product'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
services:
2+
apigee_edge_actions.edge_entity_type_manager:
3+
class: Drupal\apigee_edge_actions\ApigeeActionsEntityTypeHelper
4+
arguments: ['@entity_type.manager']
5+
logger.channel.apigee_edge_actions:
6+
parent: logger.channel_base
7+
arguments: ['apigee_edge_actions']
8+
apigee_edge_actions.events_subscriber:
9+
class: Drupal\apigee_edge_actions\EventSubscriber\AppCredentialEventSubscriber
10+
arguments:
11+
['@entity_type.manager', '@event_dispatcher', '@current_user', '@logger.channel.apigee_edge_actions']
12+
tags:
13+
- { name: 'event_subscriber' }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
/**
4+
* @file
5+
* Implements tokens for Apigee Edge entities.
6+
*/
7+
8+
/**
9+
* Copyright 2020 Google Inc.
10+
*
11+
* This program is free software; you can redistribute it and/or
12+
* modify it under the terms of the GNU General Public License
13+
* version 2 as published by the Free Software Foundation.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License
21+
* along with this program; if not, write to the Free Software
22+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23+
* MA 02110-1301, USA.
24+
*/
25+
26+
27+
use Drupal\apigee_edge\Entity\EdgeEntityInterface;
28+
use Drupal\Component\Utility\Html;
29+
use Drupal\Core\Render\BubbleableMetadata;
30+
31+
/**
32+
* Implements hook_token_info_alter().
33+
*/
34+
function apigee_edge_actions_token_info_alter(&$info) {
35+
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $apigee_entity_types */
36+
$apigee_entity_types = Drupal::service('apigee_edge_actions.edge_entity_type_manager')->getEntityTypes();
37+
$type_info = Drupal::service('plugin.manager.field.field_type')->getDefinitions();
38+
39+
foreach ($apigee_entity_types as $entity_type) {
40+
$token_type = $entity_type->get('token_type');
41+
42+
if (!isset($info['types'][$token_type]) || !isset($info['tokens'][$token_type])) {
43+
$info['types'][$entity_type->id()] = [
44+
'name' => $entity_type->getLabel(),
45+
'needs-data' => $entity_type->id(),
46+
'description' => t('Tokens related to @name.', [
47+
'@name' => $entity_type->getPluralLabel(),
48+
]),
49+
'module' => 'apigee_edge_actions',
50+
];
51+
52+
$fields = Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type->id());
53+
foreach ($fields as $field_name => $field) {
54+
/** @var \Drupal\field\FieldStorageConfigInterface $field */
55+
$params['@type'] = $type_info[$field->getType()]['label'];
56+
$description = t('@type field.', $params);
57+
58+
$labels = _token_field_label($entity_type->id(), $field->getName());
59+
$label = array_shift($labels);
60+
if (!empty($labels)) {
61+
$params['%labels'] = implode(', ', $labels);
62+
$description = t('@type field. Also known as %labels.', $params);
63+
}
64+
65+
$info['tokens'][$token_type][$field_name] = [
66+
'name' => Html::escape($label),
67+
'description' => $description,
68+
'module' => 'token',
69+
];
70+
}
71+
}
72+
}
73+
}
74+
75+
/**
76+
* Implements hook_tokens().
77+
*/
78+
function apigee_edge_actions_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
79+
$replacements = [];
80+
81+
if ($type == 'entity' && !empty($data['entity_type']) && !empty($data['entity']) && !empty($data['token_type'])) {
82+
/* @var \Drupal\Core\Entity\ContentEntityInterface $entity */
83+
$entity = $data['entity'];
84+
85+
if ($entity instanceof EdgeEntityInterface) {
86+
foreach ($tokens as $field_name => $original) {
87+
// Ensure entity has requested field and is not empty.
88+
if (!$entity->hasField($field_name) || $entity->get($field_name)->isEmpty()) {
89+
continue;
90+
}
91+
92+
$replacements[$original] = $entity->get($field_name)->value;
93+
}
94+
}
95+
}
96+
97+
return $replacements;
98+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "drupal/apigee_edge_actions",
3+
"description": "Rules integration for Apigee Edge.",
4+
"type": "drupal-module",
5+
"license": "GPL-2.0-or-later",
6+
"require": {
7+
"php": ">=7.1",
8+
"drupal/apigee_edge": "*",
9+
"drupal/rules": "^3.0@alpha"
10+
},
11+
"config": {
12+
"sort-packages": true
13+
},
14+
"minimum-stability": "dev",
15+
"prefer-stable": true
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: Apigee Edge Actions Debug
2+
description: Logs debug information for Apigee Edge Actions.
3+
package: Apigee (Experimental)
4+
type: module
5+
core: 8.x
6+
dependencies:
7+
- apigee_edge_actions:apigee_edge_actions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
services:
2+
apigee_edge_actions_debug_subscriber:
3+
class: 'Drupal\apigee_edge_actions_debug\EventSubscriber\ApigeeEdgeActionsDebugEventSubscriber'
4+
arguments:
5+
['@logger.channel.apigee_edge_actions']
6+
tags:
7+
- { name: 'event_subscriber' }

0 commit comments

Comments
 (0)