Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRUP-610] Add url as source for apidocs spec file and (DRUP-459) allow re-fetching it afterwards. #2

Merged
merged 50 commits into from
May 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
cdadac2
DRUP-624 Add revisions to API Docs.
arlina-espinoza Mar 16, 2019
09322c7
DRUP-624 Add revisioning tests to API Docs.
arlina-espinoza Mar 19, 2019
c689b4c
DRUP-624 Add revisioning permissions with tests to API Docs.
arlina-espinoza Mar 20, 2019
da963d0
DRUP-624 Add ApiDoc entity settings for default revision.
arlina-espinoza Mar 28, 2019
84f586e
DRUP-624 Fix code sniffer validations.
arlina-espinoza Mar 28, 2019
fed9ecb
DRUP-624 Add revisions link to local tasks.
arlina-espinoza Apr 6, 2019
6c4886c
DRUP-624 ApiDocAccessControlHandler implements EntityHandlerInterface.
arlina-espinoza Apr 10, 2019
96a9f9f
DRUP-624 Improving code from PR feedback.
arlina-espinoza Apr 10, 2019
028ec86
DRUP-624 Improving code from PR feedback.
arlina-espinoza Apr 10, 2019
a2f1bc8
DRUP-624 Improving tests for revisioning.
arlina-espinoza Apr 10, 2019
d938e71
DRUP-624 Fix settings form message for apidocs.
arlina-espinoza Apr 10, 2019
9a33b38
DRUP-624 Improve ApiDocSettingsForm.
arlina-espinoza Apr 11, 2019
993225a
[DRUP-624] Remove the delete permission for `apidoc` revisions.
Jaesin May 24, 2019
c3944fd
Update apigee_api_catalog.permissions.yml
Jaesin May 25, 2019
e45bfa1
Update apigee_api_catalog.permissions.yml
Jaesin May 25, 2019
ca65b24
[DRUP-624] Translate base field labels.
Jaesin May 25, 2019
f7005aa
[DRUP-624] There shouldn’t be a need to specify the default storage h…
Jaesin May 25, 2019
9eb78cc
DRUP-610 Add url as source for apidocs spec file.
arlina-espinoza May 4, 2019
971ee81
DRUP-610 Add url as source for apidocs spec file - avoid resaving sam…
arlina-espinoza May 4, 2019
c5ff9e1
DRUP-610 Add url as source for apidocs spec file - constraint to chec…
arlina-espinoza May 4, 2019
ca81fc3
DRUP-459 Add ApiDoc operation to re-fetch OpenAPI specification file …
arlina-espinoza May 4, 2019
e24316d
DRUP-610 Add url as source for apidocs spec file - renaming operation…
arlina-espinoza May 7, 2019
28e943d
DRUP-610 Add url as source for apidocs spec file - updating README.
arlina-espinoza May 7, 2019
eceb095
DRUP-610 Add url as source for apidocs spec file - refactored logic a…
arlina-espinoza May 7, 2019
49cc614
DRUP-610 Add url as source for apidocs spec file - removed isRevision…
arlina-espinoza May 7, 2019
84db514
DRUP-610 Add url as source for apidocs spec file - fixing code sniffe…
arlina-espinoza May 7, 2019
63c671e
DRUP-610 Add url as source for apidocs spec file - rename spec_as_fil…
arlina-espinoza May 7, 2019
2b78af7
DRUP-610 Add url as source for apidocs spec file - addressing PR feed…
arlina-espinoza May 7, 2019
4ae0281
DRUP-459 Refactor API Doc open API spec fetcher as service.
arlina-espinoza May 8, 2019
55fd0bd
DRUP-610 Add url as source for apidocs spec file - use DI in field co…
arlina-espinoza May 8, 2019
09ebbd4
DRUP-459 Refactor API Doc open API spec fetcher as service - bugfix.
arlina-espinoza May 8, 2019
61400ea
DRUP-459 API Doc open API spec fetcher - filesystem validations.
arlina-espinoza May 8, 2019
af8ed99
DRUP-610 Show message when refetching but using file a source.
arlina-espinoza May 8, 2019
52cfd07
DRUP-610 Replace file_get_contents() with http_client service.
arlina-espinoza May 10, 2019
c4758b7
DRUP-459 API Doc open API spec fetcher - rename stuff.
arlina-espinoza May 10, 2019
d5bdecb
DRUP-610 Code sniffer fixes.
arlina-espinoza May 10, 2019
b170d1b
[DRUP-610] Fixes the `apidoc` entity test.
Jaesin May 14, 2019
245de2a
[DRUP-610] Adds access control to the reimport `apidoc` entity operat…
Jaesin May 14, 2019
078a98b
[DRUP-610] Rename the spec fetch er service.
Jaesin May 16, 2019
7a0f19c
[Cleanup] Move entity classes under `Entity`.
Jaesin May 16, 2019
d141742
[DRUP-610] Optimizations/suggestions from `https://github.com/apigee/…
Jaesin May 16, 2019
ffd3900
[DRUP-610] Simplify logging sand remove unneeded parameters.
Jaesin May 16, 2019
d373b6f
[DRUP-610] No need to log “nothing to do” during `fetchSpec` for file…
Jaesin May 16, 2019
d823512
[DRUP-610] Adds todo about validation.
Jaesin May 16, 2019
ec769ac
[DRUP-610] Require the `file_link` module in `composer.json`.
Jaesin May 17, 2019
f0db112
[DRUP-610] Remove unnecessary trait from the APIDOc entity.
Jaesin May 23, 2019
8a0d7d2
[DRUP-610] Use string translation in spec fetcher log messages.
Jaesin May 25, 2019
45caf36
[DRUP-610] Remove the deprecated `exceptions` options.
Jaesin May 25, 2019
3b82466
Merge pull request #3 from Jaesin/8.x-1.x-DRUP-624
cnovak May 26, 2019
6f07795
Merge branch '8.x-1.x-DRUP-610-459-apidocs-add-url' of https://github…
cnovak May 26, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,28 @@ to be able to view published API documentation.

The OpenAPI spec by default is rendered using Apigee SmartDocs.

The OpenAPI spec can be directly uploaded as a file, or associated to a source location
such as Apigee Edge or a URL. A "Re-import OpenAPI spec" operation is available per
API Doc to re-import the spec file when source location changes.

The OpenAPI spec by default is shown on the API Doc detail page by default.
To render the OpenAPI spec using Swagger UI:

1. Install an enable the [Swagger UI Field Formatter](https://www.drupal.org/project/swagger_ui_formatter) module.
2. Install the Swagger UI JS library as documented [on the module page](https://www.drupal.org/project/swagger_ui_formatter).
3. Go to __Configuration > API catalog > Manage display__ in the admin menu.
4. Change "OpenAPI specification" field format to use the Swagger UI field formatter.

The API Doc is an entity, you can configure it at __Configuration > API catalog__ in the admin
menu.

The "APIs" menu link is a view, you can modify it by editing the "API Catalog" view
The "APIs" menu link is a view, you can modify it by editing the "API Catalog" view
under Structure > Views in the admin menu.

## Planned Features

- Integration with Apigee API Products
- Allow OpenAPI specs to be associated to a source location such as Apigee Edge or a URL
- Add visual notifications when source URL specs have changed on the API Doc admin screen
- Ability to update API Docs when source location changes

### Known issues

Expand All @@ -35,10 +45,10 @@ under Structure > Views in the admin menu.

## Installing

This module must be installed on a Drupal site that is managed by Composer. Drupal.org has documentation on how to
This module must be installed on a Drupal site that is managed by Composer. Drupal.org has documentation on how to
[use Composer to manage Drupal site dependencies](https://www.drupal.org/docs/develop/using-composer/using-composer-to-manage-drupal-site-dependencies)
to get you started quickly.

1. Install the module using [Composer](https://getcomposer.org/).
Composer will download the this module and all its dependencies.
**Note**: Composer must be executed at the root of your Drupal installation.
Expand Down
1 change: 1 addition & 0 deletions apigee_api_catalog.info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ configure: entity.apidoc.settings
dependencies:
- drupal:text
- drupal:file
- drupal:file_link
- apigee_edge:apigee_edge
16 changes: 14 additions & 2 deletions apigee_api_catalog.links.task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ entity.apidoc.edit_form:
title: 'Edit'

entity.apidoc.delete_form:
route_name: entity.apidoc.delete_form
base_route: entity.apidoc.canonical
route_name: entity.apidoc.delete_form
base_route: entity.apidoc.canonical
title: 'Delete'
weight: 10

Expand All @@ -25,3 +25,15 @@ apidoc.admin:
route_name: entity.apidoc.collection
base_route: system.admin_content
weight: 10

entity.apidoc.version_history:
route_name: entity.apidoc.version_history
base_route: entity.apidoc.canonical
title: 'Revisions'
weight: 15

entity.apidoc.reimport_spec_form:
route_name: entity.apidoc.reimport_spec_form
base_route: entity.apidoc.canonical
title: 'Re-import OpenAPI spec'
weight: 15
1 change: 0 additions & 1 deletion apigee_api_catalog.module
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,3 @@ function apigee_api_catalog_help($route_name, RouteMatchInterface $route_match)
default:
}
}

8 changes: 8 additions & 0 deletions apigee_api_catalog.permissions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ view published apidoc entities:

view unpublished apidoc entities:
title: 'View unpublished API docs'

view apidoc revisions:
title: 'View API Doc revisions'
description: 'To view a revision, you also need permission to view the item.'

revert apidoc revisions:
title: 'Revert API Doc revisions'
description: 'To revert a revision, you also need permission to edit the item.'
5 changes: 5 additions & 0 deletions apigee_api_catalog.services.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
services:

logger.channel.apigee_api_catalog:
parent: logger.channel_base
arguments: ['apigee_api_catalog']

apigee_api_catalog.spec_fetcher:
class: Drupal\apigee_api_catalog\SpecFetcher
arguments: ['@file_system', '@http_client', '@entity_type.manager', '@string_translation', '@messenger', '@logger.channel.apigee_api_catalog']
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"description": "Apigee API Catalog for Drupal",
"require": {
"php": ">=7.1",
"drupal/apigee_edge": "~1.0-rc4"
"drupal/apigee_edge": "~1.0-rc4",
Jaesin marked this conversation as resolved.
Show resolved Hide resolved
"drupal/file_link": "~1.0"
},
"require-dev": {
"drupal/coder": "^8.3",
Expand Down
126 changes: 107 additions & 19 deletions src/Entity/Access/ApiDocAccessControlHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,131 @@

namespace Drupal\apigee_api_catalog\Entity\Access;

use Drupal\apigee_api_catalog\Entity\ApiDocInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Access controller for the API Doc entity.
*
* @see \Drupal\apigee_api_catalog\Entity\ApiDoc.
*/
class ApiDocAccessControlHandler extends EntityAccessControlHandler {
class ApiDocAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {

/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;

/**
* Constructs an access control handler instance.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
*/
public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entityTypeManager) {
parent::__construct($entity_type);
$this->entityTypeManager = $entityTypeManager;
}

/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$entity_type,
$container->get('entity_type.manager')
);
}

/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
$parent_access = parent::checkAccess($entity, $operation, $account);

if (!$parent_access->isAllowed()) {
/** @var \Drupal\apigee_api_catalog\Entity\ApiDocInterface $entity */
switch ($operation) {
case 'view':
if (!$entity->isPublished()) {
return $parent_access->orIf(AccessResult::allowedIfHasPermission($account, 'view unpublished apidoc entities'));
}
return $parent_access->orIf(AccessResult::allowedIfHasPermission($account, 'view published apidoc entities'));

case 'update':
return $parent_access->orIf(AccessResult::allowedIfHasPermission($account, 'edit apidoc entities'));

case 'delete':
return $parent_access->orIf(AccessResult::allowedIfHasPermission($account, 'delete apidoc entities'));
}
/** @var \Drupal\apigee_api_catalog\Entity\ApiDocInterface $entity */
$access = parent::checkAccess($entity, $operation, $account);

// Access control for revisions.
if (!$entity->isDefaultRevision()) {
return $this->checkAccessRevisions($entity, $operation, $account);
}

switch ($operation) {
case 'view':
return $access->orIf($entity->isPublished()
? AccessResult::allowedIfHasPermission($account, 'view published apidoc entities')
: AccessResult::allowedIfHasPermission($account, 'view unpublished apidoc entities')
);

case 'reimport':
return AccessResult::allowedIf($entity->spec_file_source->value === ApiDocInterface::SPEC_AS_URL)
->andIf($entity->access('update', $account, TRUE));

case 'update':
return $access->orIf(AccessResult::allowedIfHasPermission($account, 'edit apidoc entities'));

case 'delete':
return $access->orIf(AccessResult::allowedIfHasPermission($account, 'delete apidoc entities'));
}

// Unknown operation, no opinion.
return $parent_access;
return $access;
}

/**
* Additional access control for revisions.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which to check access.
* @param string $operation
* The entity operation.
* @param \Drupal\Core\Session\AccountInterface $account
* The user for which to check access.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
protected function checkAccessRevisions(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\Core\Entity\EntityStorageInterface $entity_storage */
$entity_storage = $this->entityTypeManager->getStorage($this->entityTypeId);

// Must have access to the same operation on the default revision.
$default_revision = $entity_storage->load($entity->id());
$has_default_entity_rev_access = $default_revision->access($operation, $account);
if (!$has_default_entity_rev_access) {
return AccessResult::forbidden();
}

$map = [
'view' => "view apidoc revisions",
'update' => "revert apidoc revisions",
];

if (!$entity || !isset($map[$operation])) {
// If there was no entity to check against, or the $op was not one of the
// supported ones, we return access denied.
return AccessResult::forbidden();
}

$admin_permission = $this->entityType->getAdminPermission();

// Perform basic permission checks first.
if ($account->hasPermission($map[$operation]) ||
($admin_permission && $account->hasPermission($admin_permission))) {
return AccessResult::allowed();
}

return AccessResult::forbidden();
}

/**
Expand Down
Loading