Skip to content

Commit

Permalink
[#267] Add the apigee_edge_actions module (#360)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
shadcn and arlina-espinoza authored Apr 15, 2020
1 parent 22c76fc commit bd64c03
Show file tree
Hide file tree
Showing 47 changed files with 2,937 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .circleci/RoboFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ public function configureModuleDependencies()
unset($config->require->{"drupal/core"});
$config->require->{"drupal/core-recommended"} = "~8.8";

// Add rules for testing apigee_edge_actions.
$config->require->{"drupal/rules"} = "^3.0@alpha";

// We require Drupal console and drush for some tests.
$config->require->{"drupal/console"} = "~1.0";
$config->require->{"drush/drush"} = "^9.7";
Expand Down
53 changes: 53 additions & 0 deletions modules/apigee_edge_actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Apigee Edge Actions

The Apigee Edge Actions module provides rules integration for Apigee Edge. It makes it easy to automate tasks and react on events such as:

* Sending an email when an App is created.
* Notify a developer when added to a Team.
* Notify admin when an API product is added to an App.

## Events

The following events are supported out of the box:

### App
`\Drupal\apigee_edge\Entity\DeveloperApp`

| Event | Name |
|---|---|
| After saving a new App | `apigee_edge_actions_entity_insert:developer_app` |
| After deleting an App | `apigee_edge_actions_entity_delete:developer_app` |
| After updating an App | `apigee_edge_actions_entity_insert:developer_app` |
| After adding an API Product | `apigee_edge_actions_entity_add_product:developer_app` |
| After removing an API Product | `apigee_edge_actions_entity_remove_product:developer_app` |

### Team App
`\Drupal\apigee_edge_teams\Entity\TeamApp`

| Event | Name |
|---|---|
| After saving a new Team App | `apigee_edge_actions_entity_insert:team_app` |
| After deleting an Team App | `apigee_edge_actions_entity_delete:team_app` |
| After updating an Team App | `apigee_edge_actions_entity_insert:team_app` |
| After adding an API Product | `apigee_edge_actions_entity_add_product:team_app` |
| After removing an API Product | `apigee_edge_actions_entity_remove_product:team_app` |

### Team
`\Drupal\apigee_edge_teams\Entity\Team`

| Event | Name |
|---|---|
| After saving a new Team | `apigee_edge_actions_entity_insert:team` |
| After deleting an Team | `apigee_edge_actions_entity_delete:team` |
| After updating an Team | `apigee_edge_actions_entity_insert:team` |
| After adding a team member | `apigee_edge_actions_entity_add_member:team` |
| After removing a team member | `apigee_edge_actions_entity_remove_member:team` |

## Examples

The `apigee_edge_actions_examples` module ships with some example rules you can use to test:

1. Log a message when team is deleted.
2. Notify developer when added to a team
3. Notify developer when adding a new app
4. Notify site admins when app is created
9 changes: 9 additions & 0 deletions modules/apigee_edge_actions/apigee_edge_actions.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: Apigee Edge Actions
description: Rules integration for Apigee Edge.
package: Apigee (Experimental)
type: module
core: 8.x
configure: entity.rules_reaction_rule.collection
dependencies:
- apigee_edge:apigee_edge
- rules:rules
120 changes: 120 additions & 0 deletions modules/apigee_edge_actions/apigee_edge_actions.module
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

/**
* Copyright 2020 Google Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

use Drupal\apigee_edge\Entity\DeveloperAppInterface;
use Drupal\apigee_edge_actions\Event\EdgeEntityEventEdge;
use Drupal\apigee_edge\Entity\AppInterface;
use Drupal\apigee_edge_actions\Plugin\RulesAction\SystemMailToUsersOfRole;
use Drupal\Core\Entity\EntityInterface;

/**
* Implements hook_entity_insert().
*/
function apigee_edge_actions_entity_insert(EntityInterface $entity) {
_apigee_edge_actions_dispatch_entity_event($entity, 'insert');
}

/**
* Implements hook_entity_delete().
*/
function apigee_edge_actions_entity_delete(EntityInterface $entity) {
_apigee_edge_actions_dispatch_entity_event($entity, 'delete');
}

/**
* Implements hook_entity_update().
*/
function apigee_edge_actions_entity_update(EntityInterface $entity) {
_apigee_edge_actions_dispatch_entity_event($entity, 'update');
}

/**
* Implements hook_archiver_info_alter().
*/
function apigee_edge_actions_rules_action_info_alter(&$info) {
// Override the class for this rule action to handle param upcasting.
// @see https://www.drupal.org/project/rules/issues/2800749
$info['rules_email_to_users_of_role']['class'] = SystemMailToUsersOfRole::class;
}

/**
* Helper to dispatch an entity event.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
* @param string $event_name
* The event name.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
function _apigee_edge_actions_dispatch_entity_event(EntityInterface $entity, string $event_name) {
if (!Drupal::service('apigee_edge_actions.edge_entity_type_manager')
->isFieldableEdgeEntityType($entity->getEntityType())) {
return;
}

$dispatched_event_name = "apigee_edge_actions_entity_$event_name:{$entity->getEntityTypeId()}";

$arguments = [
$entity->getEntityTypeId() => $entity
];

// Note: Refactor this to plugins if more entity types requires custom
// arguments.
if ($entity instanceof AppInterface) {
if ($entity instanceof DeveloperAppInterface) {
// $entity->getCreatedBy() is deprecated, so to get the developer Drupal
// account we need to load the developer by UUID, then load the user by
// email.
// Note: $entity->getAppOwner() returns a developer UUID, which is
// different from a user's UUID, so we load the developer first and then
// the account.
$developer = Drupal::entityTypeManager()
->getStorage('developer')
->load($entity->getAppOwner());
$user_id = $developer->getEmail();
}
else {
/** @var \Drupal\apigee_edge_teams\Entity\TeamAppInterface $entity */
// For TeamApps, getAppOwner() is a team name, not a developer or email,
// and we cannot rely on getCreatedBy() as it is deprecated, so we
// default to the current user for the developer.
$user_id = Drupal::currentUser()->getEmail();

// Add the team.
$team = Drupal::entityTypeManager()
->getStorage('team')
->load($entity->getAppOwner());
$arguments['team'] = $team;
}

// Add the developer.
$arguments['developer'] = user_load_by_mail($user_id);
}

if ($event_name === 'update') {
$arguments["{$entity->getEntityTypeId()}_unchanged"] = $entity->original;
}

/** @var \Drupal\apigee_edge\Entity\EdgeEntityInterface $entity */
Drupal::service('event_dispatcher')
->dispatch($dispatched_event_name, new EdgeEntityEventEdge($entity, $arguments));
}
27 changes: 27 additions & 0 deletions modules/apigee_edge_actions/apigee_edge_actions.rules.events.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apigee_edge_actions_entity_insert:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityInsertEventDeriver'
event: 'insert'

apigee_edge_actions_entity_delete:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityDeleteEventDeriver'
event: 'delete'

apigee_edge_actions_entity_update:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityUpdateEventDeriver'
event: 'update'

apigee_edge_actions_entity_add_member:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityAddMemberEventDeriver'
event: 'add_member'

apigee_edge_actions_entity_remove_member:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityRemoveMemberEventDeriver'
event: 'remove_member'

apigee_edge_actions_entity_add_product:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityAddProductEventDeriver'
event: 'add_product'

apigee_edge_actions_entity_remove_product:
deriver: '\Drupal\apigee_edge_actions\Plugin\RulesEvent\EdgeEntityRemoveProductEventDeriver'
event: 'remove_product'
13 changes: 13 additions & 0 deletions modules/apigee_edge_actions/apigee_edge_actions.services.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
services:
apigee_edge_actions.edge_entity_type_manager:
class: Drupal\apigee_edge_actions\ApigeeActionsEntityTypeHelper
arguments: ['@entity_type.manager']
logger.channel.apigee_edge_actions:
parent: logger.channel_base
arguments: ['apigee_edge_actions']
apigee_edge_actions.events_subscriber:
class: Drupal\apigee_edge_actions\EventSubscriber\AppCredentialEventSubscriber
arguments:
['@entity_type.manager', '@event_dispatcher', '@current_user', '@logger.channel.apigee_edge_actions']
tags:
- { name: 'event_subscriber' }
98 changes: 98 additions & 0 deletions modules/apigee_edge_actions/apigee_edge_actions.tokens.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

/**
* @file
* Implements tokens for Apigee Edge entities.
*/

/**
* Copyright 2020 Google Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/


use Drupal\apigee_edge\Entity\EdgeEntityInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Render\BubbleableMetadata;

/**
* Implements hook_token_info_alter().
*/
function apigee_edge_actions_token_info_alter(&$info) {
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $apigee_entity_types */
$apigee_entity_types = Drupal::service('apigee_edge_actions.edge_entity_type_manager')->getEntityTypes();
$type_info = Drupal::service('plugin.manager.field.field_type')->getDefinitions();

foreach ($apigee_entity_types as $entity_type) {
$token_type = $entity_type->get('token_type');

if (!isset($info['types'][$token_type]) || !isset($info['tokens'][$token_type])) {
$info['types'][$entity_type->id()] = [
'name' => $entity_type->getLabel(),
'needs-data' => $entity_type->id(),
'description' => t('Tokens related to @name.', [
'@name' => $entity_type->getPluralLabel(),
]),
'module' => 'apigee_edge_actions',
];

$fields = Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type->id());
foreach ($fields as $field_name => $field) {
/** @var \Drupal\field\FieldStorageConfigInterface $field */
$params['@type'] = $type_info[$field->getType()]['label'];
$description = t('@type field.', $params);

$labels = _token_field_label($entity_type->id(), $field->getName());
$label = array_shift($labels);
if (!empty($labels)) {
$params['%labels'] = implode(', ', $labels);
$description = t('@type field. Also known as %labels.', $params);
}

$info['tokens'][$token_type][$field_name] = [
'name' => Html::escape($label),
'description' => $description,
'module' => 'token',
];
}
}
}
}

/**
* Implements hook_tokens().
*/
function apigee_edge_actions_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
$replacements = [];

if ($type == 'entity' && !empty($data['entity_type']) && !empty($data['entity']) && !empty($data['token_type'])) {
/* @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $data['entity'];

if ($entity instanceof EdgeEntityInterface) {
foreach ($tokens as $field_name => $original) {
// Ensure entity has requested field and is not empty.
if (!$entity->hasField($field_name) || $entity->get($field_name)->isEmpty()) {
continue;
}

$replacements[$original] = $entity->get($field_name)->value;
}
}
}

return $replacements;
}
16 changes: 16 additions & 0 deletions modules/apigee_edge_actions/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "drupal/apigee_edge_actions",
"description": "Rules integration for Apigee Edge.",
"type": "drupal-module",
"license": "GPL-2.0-or-later",
"require": {
"php": ">=7.1",
"drupal/apigee_edge": "*",
"drupal/rules": "^3.0@alpha"
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: Apigee Edge Actions Debug
description: Logs debug information for Apigee Edge Actions.
package: Apigee (Experimental)
type: module
core: 8.x
dependencies:
- apigee_edge_actions:apigee_edge_actions
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
apigee_edge_actions_debug_subscriber:
class: 'Drupal\apigee_edge_actions_debug\EventSubscriber\ApigeeEdgeActionsDebugEventSubscriber'
arguments:
['@logger.channel.apigee_edge_actions']
tags:
- { name: 'event_subscriber' }
Loading

0 comments on commit bd64c03

Please sign in to comment.