Enhance WHMCS integration with mTLS support and product mapping features. Added mTLS configuration options, updated API endpoints for mTLS status and fingerprint registration, and implemented product validation API. Updated database schema and documentation accordingly.
This commit is contained in:
@@ -4,14 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
final class HexaGameCloudAddonApiClient
|
||||
{
|
||||
private array $mtls = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly string $baseUrl,
|
||||
private readonly string $integrationId,
|
||||
private readonly string $apiSecret,
|
||||
array $mtls = [],
|
||||
) {
|
||||
if ($this->baseUrl === '' || $this->integrationId === '' || $this->apiSecret === '') {
|
||||
throw new RuntimeException('API URL, integration ID and secret are required');
|
||||
}
|
||||
|
||||
$this->mtls = $mtls;
|
||||
}
|
||||
|
||||
public function health(): array
|
||||
@@ -58,6 +63,36 @@ final class HexaGameCloudAddonApiClient
|
||||
);
|
||||
}
|
||||
|
||||
public function listPlans(): array
|
||||
{
|
||||
return $this->request('GET', '/api/v1/integrations/whmcs/catalog/plans');
|
||||
}
|
||||
|
||||
public function validatePlan(string $planSlug): array
|
||||
{
|
||||
return $this->request('POST', '/api/v1/integrations/whmcs/catalog/validate-plan', [
|
||||
'planSlug' => $planSlug,
|
||||
]);
|
||||
}
|
||||
|
||||
public function registerMtlsFingerprint(string $fingerprint, ?string $subject = null): array
|
||||
{
|
||||
return $this->request(
|
||||
'PUT',
|
||||
'/api/v1/integrations/whmcs/mtls/fingerprint',
|
||||
array_filter([
|
||||
'fingerprint' => $fingerprint,
|
||||
'subject' => $subject,
|
||||
]),
|
||||
'mtls:register:' . date('Y-m-d')
|
||||
);
|
||||
}
|
||||
|
||||
public function mtlsStatus(): array
|
||||
{
|
||||
return $this->request('GET', '/api/v1/integrations/whmcs/mtls/status');
|
||||
}
|
||||
|
||||
private function request(string $method, string $pathWithQuery, array $body = [], ?string $idempotencySuffix = null): array
|
||||
{
|
||||
$pathParts = explode('?', $pathWithQuery, 2);
|
||||
@@ -92,6 +127,20 @@ final class HexaGameCloudAddonApiClient
|
||||
$signature = hash_hmac('sha256', $signatureBase, $this->apiSecret);
|
||||
$requestUrl = rtrim($this->baseUrl, '/') . $path . ($canonicalQuery !== '' ? ('?' . $canonicalQuery) : '');
|
||||
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'X-HGC-Integration-ID: ' . $this->integrationId,
|
||||
'X-HGC-Timestamp: ' . $timestamp,
|
||||
'X-HGC-Nonce: ' . $nonce,
|
||||
'X-HGC-Idempotency-Key: ' . $idempotencyKey,
|
||||
'X-HGC-Signature: ' . $signature,
|
||||
];
|
||||
|
||||
if ($this->mtls !== [] && class_exists('HexaGameCloudMtlsConfig')) {
|
||||
$headers = array_merge($headers, HexaGameCloudMtlsConfig::fingerprintHeader($this->mtls));
|
||||
}
|
||||
|
||||
$ch = curl_init($requestUrl);
|
||||
if ($ch === false) {
|
||||
throw new RuntimeException('Unable to initialize HTTP client');
|
||||
@@ -101,18 +150,14 @@ final class HexaGameCloudAddonApiClient
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'X-HGC-Integration-ID: ' . $this->integrationId,
|
||||
'X-HGC-Timestamp: ' . $timestamp,
|
||||
'X-HGC-Nonce: ' . $nonce,
|
||||
'X-HGC-Idempotency-Key: ' . $idempotencyKey,
|
||||
'X-HGC-Signature: ' . $signature,
|
||||
],
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
CURLOPT_POSTFIELDS => $bodyJson,
|
||||
]);
|
||||
|
||||
if ($this->mtls !== [] && class_exists('HexaGameCloudMtlsConfig')) {
|
||||
HexaGameCloudMtlsConfig::applyToCurl($ch, $this->mtls);
|
||||
}
|
||||
|
||||
$responseBody = curl_exec($ch);
|
||||
$statusCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlError = curl_error($ch);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use WHMCS\Database\Capsule;
|
||||
|
||||
final class HexaGameCloudProductMappingStorage
|
||||
{
|
||||
public function listMappings(): array
|
||||
{
|
||||
return Capsule::table('mod_hexagamecloud_product_mappings')
|
||||
->orderBy('whmcs_product_id', 'asc')
|
||||
->get()
|
||||
->map(static fn ($row) => (array) $row)
|
||||
->all();
|
||||
}
|
||||
|
||||
public function upsertMapping(array $input): void
|
||||
{
|
||||
Capsule::table('mod_hexagamecloud_product_mappings')->updateOrInsert(
|
||||
['whmcs_product_id' => (int) $input['whmcs_product_id']],
|
||||
[
|
||||
'whmcs_product_name' => (string) ($input['whmcs_product_name'] ?? ''),
|
||||
'plan_slug' => (string) $input['plan_slug'],
|
||||
'default_edition' => (string) ($input['default_edition'] ?? 'JAVA'),
|
||||
'default_software' => (string) ($input['default_software'] ?? 'VANILLA'),
|
||||
'default_version' => (string) ($input['default_version'] ?? '1.21.1'),
|
||||
'is_active' => !empty($input['is_active']) ? 1 : 0,
|
||||
'updated_at' => gmdate('Y-m-d H:i:s'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteMapping(int $productId): void
|
||||
{
|
||||
Capsule::table('mod_hexagamecloud_product_mappings')
|
||||
->where('whmcs_product_id', $productId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function listWhmcsProducts(): array
|
||||
{
|
||||
return Capsule::table('tblproducts')
|
||||
->where('servertype', 'hexagamecloud')
|
||||
->orderBy('name', 'asc')
|
||||
->get(['id', 'name', 'gid'])
|
||||
->map(static fn ($row) => (array) $row)
|
||||
->all();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user