Add platform admin hosting API for Ladill account provisioning.
Deploy Ladill Hosting / deploy (push) Successful in 1m29s
Deploy Ladill Hosting / deploy (push) Successful in 1m29s
Expose authenticated service endpoints for assigning, listing, renewing, and managing hosting accounts from the platform, with tests and deploy docs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\HostingAccount;
|
||||
use App\Models\HostingProduct;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PlatformHostingAdminApiTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private const API_KEY = 'test-platform-hosting-key';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config(['platform.service_api_keys' => ['account' => self::API_KEY]]);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Carbon::setTestNow();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_platform_can_assign_hosting_package_to_user(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-04-05 10:00:00');
|
||||
|
||||
$owner = User::query()->create([
|
||||
'public_id' => (string) \Illuminate\Support\Str::uuid(),
|
||||
'name' => 'Hosting Owner',
|
||||
'email' => 'owner@example.com',
|
||||
]);
|
||||
$product = $this->createHostingProduct();
|
||||
|
||||
$response = $this->withToken(self::API_KEY)
|
||||
->postJson('/api/platform/users/'.$owner->public_id.'/hosting-accounts', [
|
||||
'hosting_product_id' => $product->id,
|
||||
'duration_months' => 6,
|
||||
'primary_domain' => 'example.com',
|
||||
'username' => 'exampleuser',
|
||||
'owner_email' => $owner->email,
|
||||
'owner_name' => $owner->name,
|
||||
'assigned_by_admin' => 99,
|
||||
]);
|
||||
|
||||
$response->assertCreated()
|
||||
->assertJsonPath('data.account.username', 'exampleuser')
|
||||
->assertJsonPath('data.account.primary_domain', 'example.com')
|
||||
->assertJsonPath('data.account.status', 'active')
|
||||
->assertJsonPath('data.account.metadata.assigned_duration_months', 6)
|
||||
->assertJsonPath('data.account.metadata.assigned_by_admin', 99);
|
||||
|
||||
$account = HostingAccount::query()->where('user_id', $owner->id)->firstOrFail();
|
||||
$this->assertTrue($account->expires_at->equalTo(Carbon::parse('2026-10-05 10:00:00')));
|
||||
}
|
||||
|
||||
public function test_platform_can_list_user_hosting_accounts(): void
|
||||
{
|
||||
$owner = User::query()->create([
|
||||
'public_id' => (string) \Illuminate\Support\Str::uuid(),
|
||||
'name' => 'Hosting Owner',
|
||||
'email' => 'owner@example.com',
|
||||
]);
|
||||
$product = $this->createHostingProduct();
|
||||
|
||||
HostingAccount::query()->create([
|
||||
'user_id' => $owner->id,
|
||||
'hosting_product_id' => $product->id,
|
||||
'username' => 'listeduser',
|
||||
'type' => 'shared',
|
||||
'status' => 'active',
|
||||
'metadata' => ['assigned_duration_months' => 3],
|
||||
]);
|
||||
|
||||
$response = $this->withToken(self::API_KEY)
|
||||
->getJson('/api/platform/users/'.$owner->public_id.'/hosting-accounts');
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonCount(1, 'data')
|
||||
->assertJsonPath('data.0.username', 'listeduser');
|
||||
}
|
||||
|
||||
public function test_platform_can_update_duration_and_renew(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-04-05 10:00:00');
|
||||
|
||||
$owner = User::query()->create([
|
||||
'public_id' => (string) \Illuminate\Support\Str::uuid(),
|
||||
'name' => 'Hosting Owner',
|
||||
'email' => 'owner@example.com',
|
||||
]);
|
||||
$product = $this->createHostingProduct();
|
||||
|
||||
$account = HostingAccount::query()->create([
|
||||
'user_id' => $owner->id,
|
||||
'hosting_product_id' => $product->id,
|
||||
'username' => 'durationuser',
|
||||
'type' => 'shared',
|
||||
'status' => 'active',
|
||||
'expires_at' => Carbon::parse('2026-05-05 10:00:00'),
|
||||
'metadata' => ['assigned_duration_months' => 1],
|
||||
]);
|
||||
|
||||
$this->withToken(self::API_KEY)
|
||||
->patchJson('/api/platform/hosting-accounts/'.$account->id.'/duration', [
|
||||
'duration_months' => 12,
|
||||
'admin_id' => 7,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.metadata.assigned_duration_months', 12);
|
||||
|
||||
$account->refresh();
|
||||
$this->assertTrue($account->expires_at->equalTo(Carbon::parse('2027-04-05 10:00:00')));
|
||||
|
||||
$this->withToken(self::API_KEY)
|
||||
->postJson('/api/platform/hosting-accounts/'.$account->id.'/renew', ['admin_id' => 7])
|
||||
->assertOk();
|
||||
|
||||
$account->refresh();
|
||||
$this->assertTrue($account->expires_at->equalTo(Carbon::parse('2028-04-05 10:00:00')));
|
||||
}
|
||||
|
||||
public function test_unauthenticated_platform_requests_are_rejected(): void
|
||||
{
|
||||
$this->getJson('/api/platform/hosting-products')->assertUnauthorized();
|
||||
}
|
||||
|
||||
private function createHostingProduct(): HostingProduct
|
||||
{
|
||||
return HostingProduct::query()->create([
|
||||
'name' => 'Admin Assigned Shared Hosting',
|
||||
'slug' => 'admin-assigned-shared-hosting',
|
||||
'category' => 'shared',
|
||||
'type' => 'single_domain',
|
||||
'price_monthly' => 10,
|
||||
'price_quarterly' => 30,
|
||||
'price_yearly' => 120,
|
||||
'price_biennial' => 240,
|
||||
'currency' => 'GHS',
|
||||
'max_domains' => 1,
|
||||
'is_active' => true,
|
||||
'is_visible' => true,
|
||||
'sort_order' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user