Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 3 additions & 5 deletions app/Actions/Licenses/DeleteLicense.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@

class DeleteLicense
{
public function __construct(
protected Anystack $anystack
) {}

/**
* Handle the deletion of a license.
*/
public function handle(License $license, bool $deleteFromAnystack = true): bool
{
if ($deleteFromAnystack) {
$this->anystack->deleteLicense($license->anystack_product_id, $license->anystack_id);
Anystack::api()
->license($license->anystack_id, $license->anystack_product_id)
->delete();
}

return $license->delete();
Expand Down
8 changes: 3 additions & 5 deletions app/Actions/Licenses/SuspendLicense.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@

class SuspendLicense
{
public function __construct(
protected Anystack $anystack
) {}

/**
* Handle the suspension of a license.
*/
public function handle(License $license): License
{
$this->anystack->suspendLicense($license->anystack_product_id, $license->anystack_id);
Anystack::api()
->license($license->anystack_id, $license->anystack_product_id)
->suspend();

$license->update([
'is_suspended' => true,
Expand Down
5 changes: 4 additions & 1 deletion app/Filament/Resources/LicenseResource/Pages/EditLicense.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ protected function getHeaderActions(): array
->visible(fn () => filled($this->record->anystack_id))
->action(function () {
try {
$response = app(Anystack::class)->getLicense($this->record->anystack_product_id, $this->record->anystack_id);
$response = Anystack::api()
->license($this->record->anystack_id, $this->record->anystack_product_id)
->retrieve();

dispatch_sync(new UpsertLicenseFromAnystackLicense($response->json('data')));

Notification::make()
Expand Down
6 changes: 4 additions & 2 deletions app/Filament/Resources/LicenseResource/Pages/ListLicenses.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ protected function getHeaderActions(): array
])
->action(function (array $data) {
try {
$productId = Subscription::Mini->anystackProductId();
$response = app(Anystack::class)->getLicense($productId, $data['anystack_id']);
$response = Anystack::api()
->license($data['anystack_id'], Subscription::Mini->anystackProductId()) // any plan's product id will work
->retrieve();

$licenseData = $response->json('data');

dispatch_sync(new UpsertLicenseFromAnystackLicense($licenseData));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ protected function getHeaderActions(): array
])
->action(function (array $data) {
try {
$productId = Subscription::Mini->anystackProductId();
$response = app(Anystack::class)->getLicense($productId, $data['anystack_id']);
$response = Anystack::api()
->license($data['anystack_id'], Subscription::Mini->anystackProductId()) // any plan's product id will work
->retrieve();

$licenseData = $response->json('data');

dispatch_sync(new UpsertLicenseFromAnystackLicense($licenseData));
Expand Down
67 changes: 16 additions & 51 deletions app/Services/Anystack/Anystack.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,34 @@

namespace App\Services\Anystack;

use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use App\Models\User;
use Illuminate\Http\Client\HttpClientException;

class Anystack
final class Anystack
{
/**
* Create a new Anystack API client.
*/
public function client(): PendingRequest
public static function api(?string $apiKey = null): AnystackClient
{
return Http::withToken(config('services.anystack.key'))
->acceptJson()
->asJson();
}
if (! ($apiKey ??= config('services.anystack.key'))) {
throw new HttpClientException('Anystack API key is not configured.');
}

/**
* Suspend a license on AnyStack.
*
* @param string $productId The AnyStack product ID
* @param string $licenseId The AnyStack license ID
* @return Response The API response
*
* @throws \Illuminate\Http\Client\RequestException If the request fails
*/
public function suspendLicense(string $productId, string $licenseId): Response
{
return $this->client()
->patch("https://api.anystack.sh/v1/products/{$productId}/licenses/{$licenseId}", [
'suspended' => true,
])
->throw();
return app(AnystackClient::class, ['apiKey' => $apiKey]);
}

/**
* Delete a license on AnyStack.
*
* @param string $productId The AnyStack product ID
* @param string $licenseId The AnyStack license ID
* @return Response The API response
*
* @throws \Illuminate\Http\Client\RequestException If the request fails
*/
public function deleteLicense(string $productId, string $licenseId): Response
public static function findContact(string $contactUuid): ?User
{
return $this->client()
->delete("https://api.anystack.sh/v1/products/{$productId}/licenses/{$licenseId}")
->throw();
return User::query()
->where('anystack_contact_id', $contactUuid)
->first();
}

/**
* Retrieve a license from AnyStack.
*
* @param string $productId The AnyStack product ID
* @param string $licenseId The AnyStack license ID
* @return Response The API response
*
* @throws \Illuminate\Http\Client\RequestException If the request fails
*/
public function getLicense(string $productId, string $licenseId): Response
public static function findContactOrFail(string $contactUuid): User
{
return $this->client()
->get("https://api.anystack.sh/v1/products/{$productId}/licenses/{$licenseId}")
->throw();
return User::query()
->where('anystack_contact_id', $contactUuid)
->firstOrFail();
}
}
49 changes: 49 additions & 0 deletions app/Services/Anystack/AnystackClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace App\Services\Anystack;

use App\Enums\Subscription;
use App\Services\Anystack\Resources\License;
use App\Services\Anystack\Resources\Licenses;
use App\Services\Anystack\Resources\Products;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;

final class AnystackClient
{
public function __construct(
public readonly string $apiKey,
) {}

public function products(): Products
{
return new Products($this->prepareRequest());
}

/**
* Get the licenses resource for a product on Anystack.
*/
public function licenses(?string $productId = null): Licenses
{
$productId ??= Subscription::Mini->anystackProductId();

return new Licenses($this->prepareRequest(), $productId);
}

public function license(string $id, ?string $productId = null): License
{
return $this->licenses($productId)->id($id);
}

/**
* Create a new Anystack API client.
*/
public function prepareRequest(): PendingRequest
{
return Http::withToken($this->apiKey)
->baseUrl('https://api.anystack.sh/v1/')
->acceptJson()
->asJson()
->throw();
}
}
47 changes: 47 additions & 0 deletions app/Services/Anystack/Resources/License.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Services\Anystack\Resources;

use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;

final class License
{
public function __construct(
private readonly PendingRequest $client,
private readonly string $productId,
private readonly string $licenseId,
) {}

public function retrieve(): Response
{
return $this->client->get($this->baseUrl());
}

public function update(array $data): Response
{
return $this->client->patch($this->baseUrl(), $data);
}

public function suspend(bool $suspend = true): Response
{
return $this->client->patch($this->baseUrl(), [
'suspended' => $suspend,
]);
}

public function renew(): Response
{
return $this->client->patch("{$this->baseUrl()}/renew");
}

public function delete(): Response
{
return $this->client->delete($this->baseUrl());
}

private function baseUrl(): string
{
return "products/{$this->productId}/licenses/{$this->licenseId}";
}
}
40 changes: 40 additions & 0 deletions app/Services/Anystack/Resources/Licenses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace App\Services\Anystack\Resources;

use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;

final class Licenses
{
public function __construct(
private readonly PendingRequest $client,
private readonly string $productId,
) {}

public function all(?int $page = 1): Response
{
return $this->client->get($this->url(), [
'page' => $page,
]);
}

public function create(array $data): Response
{
return $this->client->post($this->url(), $data);
}

public function id(string $licenseId): License
{
return new License(
$this->client,
$this->productId,
$licenseId,
);
}

private function url(): string
{
return "products/{$this->productId}/licenses";
}
}
29 changes: 29 additions & 0 deletions app/Services/Anystack/Resources/Product.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Services\Anystack\Resources;

use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;

final class Product
{
public function __construct(
private readonly PendingRequest $client,
private readonly string $productId,
) {}

public function licenses(): Licenses
{
return new Licenses($this->client, $this->productId);
}

public function retrieve(): Response
{
return $this->client->get($this->baseUrl());
}

private function baseUrl(): string
{
return "products/{$this->productId}";
}
}
33 changes: 33 additions & 0 deletions app/Services/Anystack/Resources/Products.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace App\Services\Anystack\Resources;

use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;

final class Products
{
public function __construct(
private readonly PendingRequest $client,
) {}

public function all(?int $page = 1): Response
{
return $this->client->get($this->url(), [
'page' => $page,
]);
}

public function id(string $productId): Product
{
return new Product(
$this->client,
$productId,
);
}

private function url(): string
{
return 'products';
}
}
Loading