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

Issue #576 Callback url issue with install file #913

Merged
merged 18 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
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
16 changes: 16 additions & 0 deletions apigee_edge.install
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Url;
use Drupal\user\RoleInterface;
use Drupal\Core\Config\FileStorage;

/**
* Implements hook_requirements().
Expand Down Expand Up @@ -373,3 +374,18 @@ function apigee_edge_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_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;
}

}
16 changes: 13 additions & 3 deletions src/Form/AppCallbackUrlSettingsForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#type' => 'textfield',
'#title' => $this->t('Pattern'),
'#default_value' => $app_settings->get('callback_url_pattern'),
'#description' => $this->t('Regular expression that a Callback URL should match. Default is "^https?:\/\/.*$" that ensures callback url starts with either <em>http://</em> or <em>https://</em>.'),
'#description' => $this->t('Regular expression that a Callback URL should match. Default is "^https?:\/\/.*$" that ensures callback url starts with either <em>http://</em> or <em>https://</em>. Avoid using delimiters.'),
'#required' => TRUE,
];
$form['callback_url']['pattern_error_message'] = [
Expand Down 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
Loading