Skip to content

Commit

Permalink
Issue2x #576 (#914)
Browse files Browse the repository at this point in the history
* Changes #576 to allow multiple protocols for callback URL

* Fixed PHPCS issues

* Minor update

* Removed url field test cases which were not valid for basic textfield

* Changes for testInvalidEdgeSideCallbackUrl class

* Updated the changes post review

* Updated the changes post review

* Removed comments

* Changes in install file only for callbackurl field

* Changes in install file only for callbackurl field

* Removed extra Filestorage from install file2x

* Test cases updated

* Changes for Warning thrown on preg_match

* Fixes for PHPCS

* Changes for pattern validator in 2x

* Changes added pattern message and delimiters 2x

* Changes for callback url pattern validation 2x

* Changes for multiple delimiters

* Changes in field description
  • Loading branch information
kedarkhaire authored Sep 8, 2023
1 parent 48c7800 commit aa3d60d
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 117 deletions.
16 changes: 16 additions & 0 deletions apigee_edge.install
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Drupal\apigee_edge\OauthTokenFileStorage;
use Drupal\apigee_edge\Plugin\EdgeKeyTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Url;
use Drupal\user\RoleInterface;
Expand Down Expand Up @@ -373,3 +374,18 @@ function apigee_edge_update_9001() {

$definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions);
}

/**
* Updates Configs for Core Entity View Display for Default Team App
*/
function apigee_edge_update_9002() {
// Update existing config.
/** @var \Drupal\Core\Config\StorageInterface $config_storage */
$config_storage = \Drupal::service('config.storage');
$module_path = \Drupal::service('extension.list.module')->getPath('apigee_edge');
$source = new FileStorage("$module_path/config/install");
$new_edge_settings = $source->read('core.entity_view_display.developer_app.developer_app.default');
$edge_settings = $config_storage->read('core.entity_view_display.developer_app.developer_app.default');
$edge_settings['content']['callbackUrl'] = $new_edge_settings['content']['callbackUrl'];
$config_storage->write('core.entity_view_display.developer_app.developer_app.default', $edge_settings);
}
5 changes: 1 addition & 4 deletions apigee_edge.module
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,7 @@ function apigee_edge_entity_extra_field_info() {
* Implements hook_field_formatter_info_alter().
*/
function apigee_edge_field_formatter_info_alter(array &$info) {
// Allows using the 'uri_link' formatter for the 'app_callback_url'
// field type, which uses it as default formatter.
// @see \Drupal\apigee_edge\Plugin\Field\FieldType\AppCallbackUrlItem
$info['uri_link']['field_types'][] = 'app_callback_url';
$info['basic_string']['field_types'][] = 'app_callback_url';
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ content:
region: content
settings: { }
third_party_settings: { }
type: uri_link
type: basic_string
createdAt:
type: timestamp_ago
label: inline
Expand Down
15 changes: 15 additions & 0 deletions modules/apigee_edge_teams/apigee_edge_teams.install
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,18 @@ function apigee_edge_teams_update_9001() {

$definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions);
}

/**
* Install Configs for Core Entity View Display for Default Team App
*/
function apigee_edge_teams_update_9002() {
// Update existing config.
/** @var \Drupal\Core\Config\StorageInterface $config_storage */
$config_storage = \Drupal::service('config.storage');
$module_path = \Drupal::service('extension.list.module')->getPath('apigee_edge_teams');
$source = new FileStorage("$module_path/config/install");
$new_team_settings = $source->read('core.entity_view_display.team_app.team_app.default');
$team_settings = $config_storage->read('core.entity_view_display.team_app.team_app.default');
$team_settings['content']['callbackUrl'] = $new_team_settings['content']['callbackUrl'];
$config_storage->write('core.entity_view_display.team_app.team_app.default', $team_settings);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ content:
region: content
settings: { }
third_party_settings: { }
type: uri_link
type: basic_string
createdAt:
type: timestamp_ago
label: inline
Expand Down
48 changes: 0 additions & 48 deletions src/Entity/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,54 +388,6 @@ protected static function propertyToBaseFieldBlackList(): array {
]);
}

/**
* {@inheritdoc}
*/
public function get($field_name) {
$value = parent::get($field_name);

// Make sure that returned callback url field values are actually valid
// URLs. Apigee Edge allows to set anything as callbackUrl value but
// Drupal can only accept valid URIs.
if ($field_name === 'callbackUrl') {
if (!$value->isEmpty()) {
foreach ($value->getValue() as $id => $item) {
try {
Url::fromUri($item['value']);
}
catch (\Exception $exception) {
$value->removeItem($id);
}
}
}
}

return $value;
}

/**
* {@inheritdoc}
*/
public function set($field_name, $value, $notify = TRUE) {
// If the callback URL value is not a valid URL then save an empty string
// as the field value and set the callbackUrl property to the original
// value. (So we can display the original (invalid URL) on the edit form.)
// This trick is not necessary if the value's type is array because in this
// case the field value is set on the developer app edit form.
if ($field_name === 'callbackUrl' && !is_array($value)) {
try {
Url::fromUri($value);
}
catch (\Exception $exception) {
/** @var \Drupal\apigee_edge\Entity\App $app */
$app = parent::set($field_name, '', $notify);
$app->setCallbackUrl($value);
return $app;
}
}
return parent::set($field_name, $value, $notify);
}

/**
* {@inheritdoc}
*/
Expand Down
33 changes: 0 additions & 33 deletions src/Entity/AppViewBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,4 @@
*/
class AppViewBuilder extends EdgeEntityViewBuilder {

/**
* {@inheritdoc}
*/
public function buildMultiple(array $build_list) {
$results = parent::buildMultiple($build_list);
foreach (Element::children($results) as $key) {
/** @var \Drupal\apigee_edge\Entity\AppInterface $app */
$app = $results[$key]["#{$this->entityTypeId}"];
// If the callback field is visible, display an error message if the
// callback url field value does not contain a valid URI.
if (array_key_exists('callbackUrl', $results[$key]) && !empty($app->getCallbackUrl()) && $app->getCallbackUrl() !== $app->get('callbackUrl')->value) {
try {
Url::fromUri($app->getCallbackUrl());
}
catch (\Exception $exception) {
$results[$key]['callback_url_error'] = [
'#theme' => 'status_messages',
'#message_list' => [
'warning' => [$this->t('The @field value should be fixed. @message', [
'@field' => $app->getFieldDefinition('callbackUrl')->getLabel(),
'@message' => $exception->getMessage(),
]),
],
],
// Display it on the top of the view.
'#weight' => -100,
];
}
}
}
return $results;
}

}
14 changes: 12 additions & 2 deletions src/Form/AppCallbackUrlSettingsForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,18 @@ public function buildForm(array $form, FormStateInterface $form_state) {
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);

if (mb_strpos($form_state->getValue(['callback_url', 'pattern'], ''), '^http') === FALSE) {
$form_state->setError($form['callback_url']['pattern'], $this->t('The pattern should start with <em>^http</em> to limit the acceptable protocols.'));
$isRegExValid = FALSE;
try {
if (@preg_match('/' . $form_state->getValue(['callback_url', 'pattern']) . '/', '') !== FALSE) {
$isRegExValid = TRUE;
}
}
catch (Exception $e) {
$isRegExValid = FALSE;
}

if (!$isRegExValid) {
$form_state->setError($form['callback_url']['pattern'], $this->t('The pattern should be a valid regular expression.'));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/Plugin/Field/FieldType/AppCallbackUrlItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

namespace Drupal\apigee_edge\Plugin\Field\FieldType;

use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;

/**
* App callback url specific plugin implementation of a URI item.
Expand All @@ -33,10 +33,10 @@
* label = @Translation("App Callback URL"),
* description = @Translation("An entity field containing a callback url for an app."),
* no_ui = TRUE,
* default_formatter = "uri_link",
* default_formatter = "basic_string",
* default_widget = "app_callback_url",
* )
*/
class AppCallbackUrlItem extends UriItem {
class AppCallbackUrlItem extends StringItem {

}
4 changes: 2 additions & 2 deletions src/Plugin/Field/FieldWidget/AppCallbackUrlWidget.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
namespace Drupal\apigee_edge\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\UriWidget;
use Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextfieldWidget;
use Drupal\Core\Form\FormStateInterface;

/**
Expand All @@ -43,7 +43,7 @@
* }
* )
*/
class AppCallbackUrlWidget extends UriWidget {
class AppCallbackUrlWidget extends StringTextfieldWidget {

/**
* {@inheritdoc}
Expand Down
44 changes: 26 additions & 18 deletions tests/src/Functional/DeveloperAppUITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ public function testCallbackUrlValidationServerSide() {
// Override default configuration.
$description = 'This is a Callback URL field.';
$this->config('apigee_edge.common_app_settings')
->set('callback_url_pattern', '^https:\/\/example.com')
->set('callback_url_pattern', '^(https?|sap):\/\/example.com')
->set('callback_url_description', $description)
->save();

Expand All @@ -548,15 +548,27 @@ public function testCallbackUrlValidationServerSide() {
$this->assertSession()->pageTextContains($description);
$this->drupalGet($app_edit_url);
$this->submitForm([], 'Save');
$this->assertSession()->pageTextContains("The URL {$callback_url} is not valid.");
$this->assertSession()->pageTextContains("Callback URL field is not in the right format.");
$this->drupalGet($app_edit_url);
$this->submitForm([
'callbackUrl[0][value]' => 'http://example.com'
'callbackUrl[0][value]' => 'map://example.com'
], 'Save');
$this->assertSession()->pageTextContains("Callback URL field is not in the right format.");
$this->drupalGet($app_edit_url);
$this->submitForm([
'callbackUrl[0][value]' => 'https://example.com'
'callbackUrl[0][value]' => 'http://example.com'
], 'Save');
$this->assertSession()->pageTextContains('App has been successfully updated.');
$this->assertSession()->pageTextContains('http://example.com');
$this->drupalGet($app_edit_url);
$this->submitForm([
'callbackUrl[0][value]' => 'sap://example.com'
], 'Save');
$this->assertSession()->pageTextContains('App has been successfully updated.');
$this->assertSession()->pageTextContains('sap://example.com');
$this->drupalGet($app_edit_url);
$this->submitForm([
'callbackUrl[0][value]' => 'https://example.com',
], 'Save');
$this->assertSession()->pageTextContains('App has been successfully updated.');
$this->assertSession()->pageTextContains('https://example.com');
Expand All @@ -570,40 +582,36 @@ public function testInvalidEdgeSideCallbackUrl() {
$this->products[] = $this->createProduct();
$callback_url = $this->randomGenerator->word(8);
$callback_url_warning_msg = "The Callback URL value should be fixed. The URI '{$callback_url}' is invalid. You must use a valid URI scheme.";
$app = $this->createDeveloperApp([
'name' => $this->randomMachineName(),
'displayName' => $this->randomString(),
'callbackUrl' => $callback_url,
],
$app = $this->createDeveloperApp(
[
'name' => $this->randomMachineName(),
'displayName' => $this->randomString(),
'callbackUrl' => $callback_url,
],
$this->account,
[
$this->products[0]->id(),
]);

]
);
$app_view_url = $app->toUrl('canonical');
$app_view_by_developer_url = $app->toUrl('canonical-by-developer');
$app_edit_form_url = $app->toUrl('edit-form');
$app_edit_form_for_developer_url = $app->toUrl('edit-form-for-developer');

$this->drupalGet($app_view_url);
$this->assertSession()->pageTextContains($callback_url_warning_msg);
$this->assertSession()->pageTextNotContains('Callback URL:');
$this->drupalGet($app_view_by_developer_url);
$this->assertSession()->pageTextContains($callback_url_warning_msg);
$this->assertSession()->pageTextNotContains('Callback URL:');

$this->drupalGet($app_edit_form_url);
$this->assertSession()->fieldValueEquals('callbackUrl[0][value]', $callback_url);
$this->drupalGet($app_edit_form_for_developer_url);
$this->assertSession()->fieldValueEquals('callbackUrl[0][value]', $callback_url);

$this->drupalGet(Url::fromRoute('entity.entity_view_display.developer_app.default'));
$this->submitForm([
'fields[callbackUrl][region]' => 'hidden'
'fields[callbackUrl][region]' => 'hidden',
], 'Save');
$this->drupalGet(Url::fromRoute('entity.entity_form_display.developer_app.default'));
$this->submitForm([
'fields[callbackUrl][region]' => 'hidden'
'fields[callbackUrl][region]' => 'hidden',
], 'Save');

$this->drupalGet($app_view_url);
Expand Down
17 changes: 12 additions & 5 deletions tests/src/FunctionalJavascript/DeveloperAppUITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function testCallbackUrlValidationClientSide() {
// Override default configuration.
$pattern_error_message = 'It must be https://example.com';
$this->config('apigee_edge.common_app_settings')
->set('callback_url_pattern', '^https:\/\/example.com')
->set('callback_url_pattern', '^(https?|sap):\/\/example.com')
->set('callback_url_pattern_error_message', $pattern_error_message)
->save();

Expand All @@ -98,16 +98,23 @@ public function testCallbackUrlValidationClientSide() {
$this->submitForm([], 'Save');
$this->createScreenshot('DeveloperAppUITest-' . __FUNCTION__);
$this->assertFalse($isValidInput());
$checkValidationMessage('Please enter a URL.');
$this->drupalGet($app_edit_url);
$this->submitForm(['callbackUrl[0][value]' => 'http://example.com'], 'Save');
$this->submitForm(['callbackUrl[0][value]' => 'map://example.com'], 'Save');
$this->createScreenshot('DeveloperAppUITest-' . __FUNCTION__);
$this->assertFalse($isValidInput());
// The format in Firefox is different, it is only one line:
// "Please match the requested format: {$pattern_description}.".
$checkValidationMessage('Please match the requested format.');
$this->assertEquals($pattern_error_message, $this->getSession()->evaluateScript('document.getElementById("edit-callbackurl-0-value").title'));
$this->drupalGet($app_edit_url);
$this->submitForm(['callbackUrl[0][value]' => 'sap://example.com'], 'Save');
$this->createScreenshot('DeveloperAppUITest-' . __FUNCTION__);
$this->assertSession()->pageTextContains('App has been successfully updated.');
$this->assertSession()->pageTextContains('sap://example.com');
$this->drupalGet($app_edit_url);
$this->submitForm(['callbackUrl[0][value]' => 'http://example.com'], 'Save');
$this->createScreenshot('DeveloperAppUITest-' . __FUNCTION__);
$this->assertSession()->pageTextContains('App has been successfully updated.');
$this->assertSession()->pageTextContains('http://example.com');
$this->drupalGet($app_edit_url);
$this->submitForm(['callbackUrl[0][value]' => 'https://example.com'], 'Save');
$this->assertSession()->pageTextContains('App has been successfully updated.');
$this->assertSession()->pageTextContains('https://example.com');
Expand Down

0 comments on commit aa3d60d

Please sign in to comment.