Skip to content

Commit

Permalink
feature: basic implementation of getCustomer
Browse files Browse the repository at this point in the history
  • Loading branch information
g105b committed Jan 31, 2024
1 parent 478c14b commit 7b8546a
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/AuthenticatedRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
namespace BrightFlair\SpektrixAPI;

class AuthenticatedRequest {
public string $httpMethod;
public readonly string $uri;
public readonly Signature $signature;

/** @param array<string, string> $kvp */
public function __construct(
string $secretKey,
Endpoint $endpoint,
string $client,
array $kvp = [],
) {
[$httpMethod, $endpointPath] = explode(
" ",
$endpoint->value,
2,
);
$bodyString = null;
if(str_contains($endpointPath, " ")) {
[$endpointPath, $bodyString] = explode(
" ",
$endpointPath,
);
}

$uri = implode("/", [
Client::BASE_URI,
$endpointPath,
]);
$uri = str_replace("{client}", $client, $uri);
foreach($kvp as $key => $value) {
$uri = str_replace(
"{" . $key . "}",
$value ?? "",
$uri,
);
}

$this->httpMethod = $httpMethod;
$this->uri = $uri;
$this->signature = new Signature(
$secretKey,
$httpMethod,
$this->uri,
$bodyString,
);
}
}
78 changes: 78 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
namespace BrightFlair\SpektrixAPI;

use Gt\Fetch\Http;
use Gt\Http\Response;
use Gt\Json\JsonObject;

readonly class Client {
const USER_AGENT = "github.com/BrightFlair/SpektrixAPI";
const BASE_URI = "https://system.spektrix.com/{client}/api";

private Http $http;

public function __construct(
private string $username,
private string $client,
private string $secretKey,
Http $fetchClient = null,
) {
$this->http = $fetchClient ?? new Http();
}

public function getCustomer(
?string $id = null,
?string $email = null,
):Customer {
$endpoint = is_null($email)
? Endpoint::getCustomerById
: Endpoint::getCustomerByEmail;
$authenticatedRequest = new AuthenticatedRequest(
$this->secretKey,
$endpoint,
$this->client,
[
"id" => $id,
"email" => $email,
]
);

if($json = $this->json($authenticatedRequest)) {
return new Customer(
$json->getString("id"),
$json->getString("email"),
firstName: $json->getString("firstName"),
lastName: $json->getString("lastName"),
mobile: $json->getString("mobile"),
);
}

throw new CustomerNotFoundException($email ?? $id);
}

private function json(AuthenticatedRequest $authenticatedRequest):?JsonObject {
$authorizationHeader = Signature::AUTH_PREFIX
. " "
. $this->username
. ":"
. base64_encode($authenticatedRequest->signature->signedString);

$httpHeaders = [
"Accept" => "application/json",
"User-agent" => Client::USER_AGENT,
"Date" => $authenticatedRequest->signature->date,
"Host" => parse_url($authenticatedRequest->uri, PHP_URL_HOST),
"Authorization" => $authorizationHeader,
];

$response = $this->http->awaitFetch($authenticatedRequest->uri, [
"method" => $authenticatedRequest->httpMethod,
"headers" => $httpHeaders,
]);
if(!$response->ok) {
throw new SpektrixAPIException($response->status);
}
return $response->awaitJson();
}

}
12 changes: 12 additions & 0 deletions src/Customer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
namespace BrightFlair\SpektrixAPI;

class Customer {
public function __construct(
public string $id,
public string $email,
public ?string $firstName = null,
public ?string $lastName = null,
public ?string $mobile = null,
) {}
}
4 changes: 4 additions & 0 deletions src/CustomerNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
namespace BrightFlair\SpektrixAPI;

class CustomerNotFoundException extends SpektrixAPIException {}
11 changes: 11 additions & 0 deletions src/Endpoint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
namespace BrightFlair\SpektrixAPI;

enum Endpoint:string {
case getCustomerById = "GET v3/customers/{id}";
case getCustomerByEmail = "GET v3/customers?email={email}";
case getAllTags = "GET v3/tags";
case getCustomerTags = "GET v3/customers/{id}/tags";
case addTagToCustomer = "POST v3/customers/{id}/tags id={tagId}";
case removeTagFromCustomer = "DELETE v3/customers/tags/{tagId}?id={id}";
}
29 changes: 29 additions & 0 deletions src/Signature.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
namespace BrightFlair\SpektrixAPI;

class Signature {
const AUTH_PREFIX = "SpektrixAPI3";
public readonly string $date;
public readonly string $signedString;

public function __construct(
string $secretKeyBase64,
string $httpMethod,
string $uri,
?string $bodyString = null,
) {
$this->date = gmdate("D, d M Y H:i:s T");
$stringToSign = $httpMethod
. "\n" . $uri
. "\n" . $this->date;
if($httpMethod !== "GET") {
$md5BodyString = md5($bodyString, true);
$base64EncodedBodyString = base64_encode($md5BodyString);
$stringToSign .= "\n$base64EncodedBodyString";
}

$decodedSecretKey = base64_decode($secretKeyBase64);
$utf8encodedStringToSign = mb_convert_encoding($stringToSign, 'UTF-8', 'ISO-8859-1');
$this->signedString = hash_hmac("sha1", $utf8encodedStringToSign, $decodedSecretKey, true);
}
}
6 changes: 6 additions & 0 deletions src/SpektrixAPIException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
namespace BrightFlair\SpektrixAPI;

use RuntimeException;

class SpektrixAPIException extends RuntimeException {}
4 changes: 4 additions & 0 deletions src/SpektrixHttpErrorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
namespace BrightFlair\SpektrixAPI;

class SpektrixHttpErrorException extends SpektrixAPIException {}
6 changes: 6 additions & 0 deletions src/Tag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
namespace BrightFlair\SpektrixAPI;

class Tag {

}

0 comments on commit 7b8546a

Please sign in to comment.