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

Adds Parsely as VIP Integration #4660

Merged
merged 68 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
4940246
➕ ADDS: integrations support from config file
mehmoodak Jul 4, 2023
26c6ac3
➕ ADDS: multisite support for vip integrations for configs
mehmoodak Jul 5, 2023
041ae78
🐛 FIX: VIP_Integrations_Test
mehmoodak Jul 5, 2023
72c6611
👌 IMPROVE: comments
mehmoodak Jul 5, 2023
a3b1b79
💫 UPDATE: parsely integration from loading files to using VIP_PARSELY…
mehmoodak Jul 5, 2023
20fb066
🐛 FIX: phpcs warnings
mehmoodak Jul 5, 2023
9702ef8
🐛 FIX: config key for network sites
mehmoodak Jul 5, 2023
133e825
➕ ADDS: support for setting up integration configs via provided filter
mehmoodak Jul 5, 2023
d6e7b3e
👌 IMPROVE: vip_config comment
mehmoodak Jul 5, 2023
6a6a13f
➕ ADDS: tests for invalid slug during activation in integrations
mehmoodak Jul 5, 2023
a220fec
🐛 FIX: typos
mehmoodak Jul 6, 2023
1db5b61
➕ ADDS: tests for ParselyIntegration
mehmoodak Jul 6, 2023
abe0386
👌 IMPROVE: refactors code
mehmoodak Jul 6, 2023
0a34274
➕ ADDS: tests for VIP Integrations
mehmoodak Jul 6, 2023
478e122
➕ ADDS: test for activate function
mehmoodak Jul 6, 2023
1365d2f
🚧 WIP: fix tests
mehmoodak Jul 6, 2023
14ce33f
➕ ADDS: test for loading the integrations on muplugins_loaded hook
mehmoodak Jul 6, 2023
3199949
➕ ADDS: test for supported integrations and refactors existing tests
mehmoodak Jul 6, 2023
808cbbf
👌 IMPROVE: fake integration
mehmoodak Jul 7, 2023
2edcde3
➕ ADDS: config file tests
mehmoodak Jul 8, 2023
89f6958
➕ ADDS: tests for is_active method
mehmoodak Jul 10, 2023
80018df
➕ ADDS: tests for set_is_active_by_vip_method
mehmoodak Jul 10, 2023
711acb8
🔨 REFACTOR: change configs to config in integration
mehmoodak Jul 10, 2023
6dc5791
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Jul 10, 2023
5c25c25
🔨 REFACTOR: filter name
mehmoodak Jul 10, 2023
578f7f6
➕ ADDS: tests for data returned from setup config filter
mehmoodak Jul 10, 2023
ad2efaf
👌 IMPROVE: encapsulation
mehmoodak Jul 10, 2023
6222a7f
➕ ADDS: tests for get_value_from_vip_config function
mehmoodak Jul 11, 2023
ab450a4
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Jul 11, 2023
c457e07
👌 IMPROVE: naming and comments
mehmoodak Jul 11, 2023
eca8f5d
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Jul 11, 2023
6c6061d
🐛 FIX: config data in tests
mehmoodak Jul 11, 2023
1825bf0
🐛 FIX: remove proxy methods from fake integration
mehmoodak Jul 11, 2023
6ded1b4
➕ ADDS: config filter on fake integration
mehmoodak Jul 11, 2023
ca90a0a
👌 IMPROVE: is_active function
mehmoodak Jul 11, 2023
0c01194
🐛 FIX: if integration is enabled by both customer and vip then vip_co…
mehmoodak Jul 11, 2023
50ed69a
👌 IMPROVE: integration methods encapsulation
mehmoodak Jul 11, 2023
4f6bd97
👌 IMPROVE: naming of util methods
mehmoodak Jul 11, 2023
de0a65a
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Jul 11, 2023
547514c
➖ REMOVE: extra methods from FakeIntegration
mehmoodak Jul 19, 2023
53733f9
➕ ADDS: config overrides in each integration
mehmoodak Jul 19, 2023
c7257c1
🐛 FIX: tests
mehmoodak Jul 19, 2023
3f527ce
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Jul 19, 2023
d511ed6
🐛 FIX: VIP Integrations tests
mehmoodak Jul 19, 2023
a6b3d86
🐛 FIX: disable integration if blocked on network site but enabled on …
mehmoodak Jul 20, 2023
682378f
✅ FEEDBACK: improve variable names
mehmoodak Jul 21, 2023
4190fcd
👌 IMPROVE: naming
mehmoodak Aug 2, 2023
90bce46
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Aug 2, 2023
0f6f396
🔨 REFACTOR: Integration base class to have only one config
mehmoodak Aug 2, 2023
a29c8e2
🔨 REFACTOR: config file name
mehmoodak Aug 3, 2023
2383dce
🐛 FIX: tests
mehmoodak Aug 3, 2023
c04b721
➖ REMOVE: wp-parsely-3.8
mehmoodak Aug 3, 2023
4e8375d
🐛 FIX: slug in test
mehmoodak Aug 3, 2023
28f53cf
👌 IMPROVE: tests for Parsely integration
mehmoodak Aug 3, 2023
a1a5ac6
👌 IMPROVE: vip-integrations tests
mehmoodak Aug 3, 2023
b113913
➕ ADDS: tests for activating the integration two times
mehmoodak Aug 3, 2023
0dd30fb
➕ ADDS: tests for activating integrations based on vip configs
mehmoodak Aug 3, 2023
2b4b7a1
➕ ADDS: test for get_integration_config
mehmoodak Aug 3, 2023
832c69d
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Aug 3, 2023
d9449a2
👌 IMPROVE: comments
mehmoodak Aug 3, 2023
266b158
🐛 FIX: removes LogicException and skip the activation if integration …
mehmoodak Aug 11, 2023
ef8ac17
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Aug 17, 2023
b4811fe
💫 UPDATE: exceptions with trigger_error
mehmoodak Aug 17, 2023
2052aad
💫 UPDATE: Change config to options which will have both common and in…
mehmoodak Aug 17, 2023
80f245b
🐛 FIX: parsely config test
mehmoodak Aug 17, 2023
9839b79
👌 IMPROVE: wp_parsely_credentials_callback
mehmoodak Aug 18, 2023
4ca731a
Merge branch 'develop' into vip-parsely-41/adds-wp-parsely-vip-integr…
mehmoodak Aug 18, 2023
b106e71
💫 UPDATE: wp_parsely_credentials_callback method access from protecte…
mehmoodak Aug 18, 2023
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
21 changes: 14 additions & 7 deletions integrations/block-data-api.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<?php
/**
* Integration: Block Data API.
*
* @package Automattic\VIP\Integrations
*/
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved

namespace Automattic\VIP\Integrations;

Expand All @@ -7,35 +12,37 @@
*
* @private
*/
class BlockDataApi extends Integration {
class BlockDataApiIntegration extends Integration {
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved

/**
* The version of the Block Data API plugin to load, that's set to the latest version.
* This should be higher than the lowestVersion set in https://github.com/Automattic/vip-go-mu-plugins-ext/blob/trunk/config.json#L63
*
* This should be higher than the lowestVersion set in "vip-block-data-api" config (https://github.com/Automattic/vip-go-mu-plugins-ext/blob/trunk/config.json)
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
*
* @var string
*/
protected string $version = '1.0';

/**
* Applies hooks to load Block Data API plugin.
*
* @param array $config Configuration array for this integration.
*
* @private
*/
public function load( array $config ): void {
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
// Wait until plugins_loaded to give precedence to the plugin in the customer repo
// Wait until plugins_loaded to give precedence to the plugin in the customer repo.
add_action( 'plugins_loaded', function() {
// Do not load plugin if already loaded by customer code
// Do not load plugin if already loaded by customer code.
if ( defined( 'VIP_BLOCK_DATA_API_LOADED' ) ) {
return;
}

// Load the version of the plugin that should be set to the latest version, otherwise if it's not found deactivate the integration
// Load the version of the plugin that should be set to the latest version, otherwise if it's not found deactivate the integration.
$load_path = WPMU_PLUGIN_DIR . '/vip-integrations/vip-block-data-api-' . $this->version . '/vip-block-data-api.php';
if ( file_exists( $load_path ) ) {
require_once $load_path;
} else {
$this->is_active = false;
$this->is_active_by_customer = false;
}
} );
}
Expand Down
185 changes: 178 additions & 7 deletions integrations/integration.php
Original file line number Diff line number Diff line change
@@ -1,57 +1,226 @@
<?php
/**
* Base class for Integration.
*
* @package Automattic\VIP\Integrations
*/

namespace Automattic\VIP\Integrations;

// phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound -- Disabling due to enums.

/**
* Enum which represent all possible status for the client integration via VIP.
*
* These should be in sync with the statuses on the backend.
*/
abstract class Client_Integration_Status {
const BLOCKED = 'blocked';
}

/**
* Enum which represent all possible status for the site integration via VIP.
*
* These should be in sync with the statuses on the backend.
*/
abstract class Site_Integration_Status {
const ENABLED = 'enabled';
const DISABLED = 'disabled';
const BLOCKED = 'blocked';
}

/**
* Abstract base class for all integration implementations.
*
* @private
*/
abstract class Integration {
/**
* Slug of the integration.
*
* @var string
*/
private string $slug;

/**
* An optional configuration array for this integration, added during activation.
*
* @var array
*/
protected array $config = [];
private array $config = [];

/**
* Configurations provided by VIP for setup.
*
* @var array {
* 'client' => array<string, string>,
* 'site' => array<string, string>,
* 'network-sites' => array<string, array<string, string>>,
* }
*
* @example
* array(
* 'client' => array( 'status' => 'blocked' ),
* 'site' => array( 'status' => 'disabled' ),
* 'network-sites' => array (
* 1 => array (
* 'status' => 'disabled',
* ),
* 2 => array (
* 'status' => 'enabled',
* ),
* 3 => array (
* 'status' => 'blocked',
* ),
* )
* );
*/
private array $vip_config = [];

/**
* A boolean indicating if this integration should be loaded. Defaults to false.
* A boolean indicating if this integration is activated by customer.
*
* @var bool
*/
protected bool $is_active = false;
public bool $is_active_by_customer = false;

/**
* Constructor.
*
* @param string $slug Slug of the integration.
*/
public function __construct( string $slug ) {
$this->slug = $slug;

$this->set_vip_config();
}

/**
* Activates this integration with an optional configuration value.
*
* @param array $config An associative array of configuration values for the integration.
* @param array $config An associative array of configuration values for the integration.
*
* @private
*/
public function activate( array $config = [] ): void {
$this->is_active = true;
$this->config = $config;
$this->is_active_by_customer = true;
$this->config = $config;
}

/**
* Returns true if this integration has been activated.
*
* @return bool
*
* @private
*/
public function is_active(): bool {
return $this->is_active;
if ( $this->is_active_by_customer ) {
return true;
}

if ( $this->is_active_by_vip() ) {
return true;
}

return false;
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Return the activation configuration for this integration.
*
* @return array<mixed>
*
* @private
*/
public function get_config(): array {
return $this->config;
}

/**
* Set setup configs provided by VIP.
*/
private function set_vip_config(): void {
$config_file_path = ABSPATH . 'config/integrations-config/' . $this->slug . '-config.php';

if ( ! is_readable( $config_file_path ) ) {
return;
}

$configs = require_once $config_file_path;

if ( is_array( $configs ) ) {
$this->vip_config = $configs;
}
}

/**
* Returns true if the integration is active by VIP.
*
* @return bool
*/
private function is_active_by_vip(): bool {
// Return false if client is blocked.
if ( $this->get_value_from_vip_config( 'client', 'status' ) === Client_Integration_Status::BLOCKED ) {
return false;
}

$site_status = $this->get_value_from_vip_config( 'site', 'status' );

// Return false if site is blocked.
if ( Site_Integration_Status::BLOCKED === $site_status ) {
return false;
}

// Check for network-site enablement if multisite.
if ( is_multisite() ) {
if ( is_network_admin() ) {
return false;
}

return $this->get_value_from_vip_config( 'network-sites', 'status' ) === Site_Integration_Status::ENABLED;
}

return Site_Integration_Status::ENABLED === $site_status; // Return site status if not multisite.
}

/**
* Get config value based on given type and key.
*
* @param string $config_type Type of the config whose data is needed i.e. client, site, network-sites etc.
* @param string $key Key of the config from which we have to extract the data.
*
* @return string
*/
private function get_value_from_vip_config( string $config_type, string $key ): string {
if ( ! isset( $this->vip_config[ $config_type ] ) ) {
return '';
}

// Look for key inside client or site config.
if ( 'network-sites' !== $config_type && isset( $this->vip_config[ $config_type ][ $key ] ) ) {
return $this->vip_config[ $config_type ][ $key ];
}

// Look for key inside network-sites config.
if ( 'network-sites' === $config_type && isset( $this->vip_config[ $config_type ][ get_current_blog_id() ] ) ) {
if ( isset( $this->vip_config[ $config_type ][ get_current_blog_id() ][ $key ] ) ) {
return $this->vip_config[ $config_type ][ get_current_blog_id() ][ $key ];
}
}

return '';
}

/**
* Get slug of the integration.
*
* @private
*/
public function get_slug(): string {
return $this->slug;
}

/**
* Abstract base for integration functionality.
* Implement custom action and filter calls to load integration here.
Expand All @@ -60,6 +229,8 @@ public function get_config(): array {
* the implementation should hook into plugins_loaded and check if
* the plugin is already loaded first.
*
* @param array $config Configuration for this integration.
*
* @private
*/
abstract public function load( array $config ): void;
Expand Down
44 changes: 21 additions & 23 deletions integrations/integrations.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<?php
/**
* Integrations.
*
* @package Automattic\VIP\Integrations
*/

namespace Automattic\VIP\Integrations;

Expand All @@ -20,41 +25,32 @@ class Integrations {
/**
* Registers an integration.
*
* @param string $slug A unique identifier for the integration.
* @param string|Integration $class_or_object Fully-qualified class or instantiated Integration object.
* @param Integration $integration Instantiated integration object.
*
* @throws InvalidArgumentException Excpetion if invalid argument are passed.
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
*
* @private
*/
public function register( string $slug, $class_or_object ): void {
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
if ( isset( $this->integrations[ $slug ] ) ) {
throw new InvalidArgumentException( sprintf( 'Integration with slug "%s" is already registered.', $slug ) );
public function register( $integration ): void {
if ( ! is_subclass_of( $integration, Integration::class ) ) {
throw new InvalidArgumentException( sprintf( 'Integration class "%s" must extend %s.', get_class( $integration ), Integration::class ) );
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
}

if ( is_object( $class_or_object ) ) {
$integration_object = $class_or_object;
} else {
if ( ! class_exists( $class_or_object ) ) {
throw new InvalidArgumentException( sprintf( 'Integration class "%s" does not exist.', $class_or_object ) );
}

$integration_object = new $class_or_object();
}
$slug = $integration->get_slug();

if ( ! is_subclass_of( $integration_object, Integration::class ) ) {
throw new InvalidArgumentException( sprintf( 'Integration class "%s" must extend %s.', get_class( $integration_object ), Integration::class ) );
if ( isset( $this->integrations[ $slug ] ) ) {
throw new InvalidArgumentException( sprintf( 'Integration with slug "%s" is already registered.', $slug ) );
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
}

$this->integrations[ $slug ] = $integration_object;
$this->integrations[ $slug ] = $integration;
}

/**
* Returns a registered integration for a key, or null if not found.
*
* @param string $slug A unique identifier for the integration.
*
* @private
*/
public function get( string $slug ): ?Integration {
private function get( string $slug ): ?Integration {
return $this->integrations[ $slug ] ?? null;
}

Expand All @@ -77,13 +73,15 @@ public function load_active(): void {
* @param string $slug A unique identifier for the integration.
* @param array $config An associative array of configuration values for the integration.
*
* @throws InvalidArgumentException Excpetion if invalid argument are passed.
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
*
* @private
*/
public function activate( string $integration_slug, array $config = [] ): void {
$integration = $this->get( $integration_slug );
public function activate( string $slug, array $config = [] ): void {
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
$integration = $this->get( $slug );

if ( null === $integration ) {
throw new InvalidArgumentException( sprintf( 'VIP Integration with slug "%s" is not a registered integration.', $integration_slug ) );
throw new InvalidArgumentException( sprintf( 'VIP Integration with slug "%s" is not a registered integration.', $integration ) );
mehmoodak marked this conversation as resolved.
Show resolved Hide resolved
}

$integration->activate( $config );
Expand Down
Loading