VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
264 lines
9.6 KiB
PHP
264 lines
9.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Http\Controllers\Hosting\HostingPanelController;
|
|
use App\Http\Controllers\Hosting\HostingProductController;
|
|
use App\Models\Domain;
|
|
use App\Models\HostedSite;
|
|
use App\Models\HostingAccount;
|
|
use App\Models\HostingNode;
|
|
use App\Models\HostingProduct;
|
|
use App\Models\User;
|
|
use App\Services\Domain\DomainDnsBlueprintService;
|
|
use App\Services\Domain\DomainVerificationService;
|
|
use App\Services\Hosting\Providers\SharedNodeProvider;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\Request;
|
|
use Tests\TestCase;
|
|
|
|
class HostingPanelDomainLinkingTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_add_domain_uses_automated_nameserver_onboarding_by_default(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$product = HostingProduct::create([
|
|
'name' => 'Multi Domain Hosting',
|
|
'slug' => 'multi-domain-hosting-test',
|
|
'category' => 'shared',
|
|
'type' => 'multi_domain',
|
|
'price_monthly' => 10,
|
|
'max_domains' => 5,
|
|
]);
|
|
|
|
$node = HostingNode::create([
|
|
'name' => 'Local Node',
|
|
'hostname' => 'local-node',
|
|
'ip_address' => '127.0.0.1',
|
|
'type' => 'shared',
|
|
'provider' => 'local',
|
|
'status' => 'active',
|
|
'ssh_port' => '22',
|
|
]);
|
|
|
|
$account = HostingAccount::unguarded(function () use ($user, $node, $product) {
|
|
return HostingAccount::create([
|
|
'user_id' => $user->id,
|
|
'hosting_product_id' => $product->id,
|
|
'hosting_node_id' => $node->id,
|
|
'username' => 'acctuser',
|
|
'primary_domain' => 'primary.example.com',
|
|
'type' => 'shared',
|
|
'status' => 'active',
|
|
'php_version' => '8.2',
|
|
]);
|
|
});
|
|
|
|
$provider = \Mockery::mock(SharedNodeProvider::class);
|
|
$provider->shouldReceive('addSite')
|
|
->once()
|
|
->withArgs(fn (HostedSite $site): bool => $site->hosting_account_id === $account->id && $site->domain === 'linked-example.com')
|
|
->andReturn([
|
|
'document_root' => '/home/acctuser/public_html/linked-example.com',
|
|
'domain' => 'linked-example.com',
|
|
]);
|
|
|
|
$verification = \Mockery::mock(DomainVerificationService::class);
|
|
$verification->shouldNotReceive('prepareNameserverZone');
|
|
$verification->shouldNotReceive('prepareManualDnsPack');
|
|
|
|
$this->app->instance(SharedNodeProvider::class, $provider);
|
|
$this->app->instance(DomainVerificationService::class, $verification);
|
|
|
|
$session = $this->app['session.store'];
|
|
$session->start();
|
|
|
|
$request = Request::create('http://localhost/hosting/panel/' . $account->id . '/domains', 'POST', [
|
|
'domain' => 'linked-example.com',
|
|
], [], [], [
|
|
'HTTP_REFERER' => 'http://localhost/hosting/accounts/' . $account->id,
|
|
]);
|
|
$request->setUserResolver(fn (): User => $user);
|
|
$request->setLaravelSession($session);
|
|
|
|
$response = $this->app->make(HostingPanelController::class)->addDomain(
|
|
$request,
|
|
$account,
|
|
$this->app->make(DomainDnsBlueprintService::class),
|
|
$this->app->make(DomainVerificationService::class),
|
|
);
|
|
|
|
$this->assertSame(302, $response->getStatusCode());
|
|
|
|
$domain = Domain::query()->where('host', 'linked-example.com')->firstOrFail();
|
|
|
|
$this->assertSame($account->id, $domain->hosting_account_id);
|
|
$this->assertSame(Domain::MODE_NS_AUTO, $domain->onboarding_mode);
|
|
$this->assertSame('managed', $domain->dns_mode);
|
|
|
|
$this->assertDatabaseHas('hosted_sites', [
|
|
'hosting_account_id' => $account->id,
|
|
'domain' => 'linked-example.com',
|
|
'domain_id' => $domain->id,
|
|
]);
|
|
}
|
|
|
|
public function test_hosting_account_page_renders_linked_domains(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$product = HostingProduct::create([
|
|
'name' => 'Multi Domain Hosting',
|
|
'slug' => 'multi-domain-account-view-test',
|
|
'category' => 'shared',
|
|
'type' => 'multi_domain',
|
|
'price_monthly' => 10,
|
|
'max_domains' => 3,
|
|
]);
|
|
|
|
$node = HostingNode::create([
|
|
'name' => 'Local Node',
|
|
'hostname' => 'local-node',
|
|
'ip_address' => '127.0.0.1',
|
|
'type' => 'shared',
|
|
'provider' => 'local',
|
|
'status' => 'active',
|
|
'ssh_port' => '22',
|
|
]);
|
|
|
|
$account = HostingAccount::unguarded(function () use ($user, $node, $product) {
|
|
return HostingAccount::create([
|
|
'user_id' => $user->id,
|
|
'hosting_product_id' => $product->id,
|
|
'hosting_node_id' => $node->id,
|
|
'username' => 'acctuser',
|
|
'primary_domain' => 'primary.example.com',
|
|
'type' => 'shared',
|
|
'status' => 'active',
|
|
'php_version' => '8.2',
|
|
]);
|
|
});
|
|
|
|
HostedSite::create([
|
|
'hosting_account_id' => $account->id,
|
|
'domain' => 'primary.example.com',
|
|
'document_root' => '/home/acctuser/public_html',
|
|
'type' => 'primary',
|
|
'status' => 'active',
|
|
'ssl_enabled' => true,
|
|
]);
|
|
|
|
HostedSite::create([
|
|
'hosting_account_id' => $account->id,
|
|
'domain' => 'linked-example.com',
|
|
'document_root' => '/home/acctuser/public_html/linked-example.com',
|
|
'type' => 'addon',
|
|
'status' => 'active',
|
|
'ssl_enabled' => false,
|
|
]);
|
|
|
|
$request = Request::create('http://localhost/hosting/accounts/' . $account->id, 'GET');
|
|
$request->setUserResolver(fn (): User => $user);
|
|
|
|
$view = $this->app->make(HostingProductController::class)->showAccount($request, $account);
|
|
$html = $view->render();
|
|
|
|
$this->assertStringContainsString('primary.example.com', $html);
|
|
$this->assertStringContainsString('linked-example.com', $html);
|
|
$this->assertStringContainsString('2 of 3 domain slots in use.', $html);
|
|
}
|
|
|
|
public function test_add_domain_does_not_restore_soft_deleted_site_from_another_account(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$otherUser = User::factory()->create();
|
|
|
|
$product = HostingProduct::create([
|
|
'name' => 'Multi Domain Hosting',
|
|
'slug' => 'multi-domain-restore-guard-test',
|
|
'category' => 'shared',
|
|
'type' => 'multi_domain',
|
|
'price_monthly' => 10,
|
|
'max_domains' => 5,
|
|
]);
|
|
|
|
$node = HostingNode::create([
|
|
'name' => 'Local Node',
|
|
'hostname' => 'local-node',
|
|
'ip_address' => '127.0.0.1',
|
|
'type' => 'shared',
|
|
'provider' => 'local',
|
|
'status' => 'active',
|
|
'ssh_port' => '22',
|
|
]);
|
|
|
|
$account = HostingAccount::unguarded(function () use ($user, $node, $product) {
|
|
return HostingAccount::create([
|
|
'user_id' => $user->id,
|
|
'hosting_product_id' => $product->id,
|
|
'hosting_node_id' => $node->id,
|
|
'username' => 'acctuser',
|
|
'primary_domain' => 'primary.example.com',
|
|
'type' => 'shared',
|
|
'status' => 'active',
|
|
'php_version' => '8.2',
|
|
]);
|
|
});
|
|
|
|
$otherAccount = HostingAccount::unguarded(function () use ($otherUser, $node, $product) {
|
|
return HostingAccount::create([
|
|
'user_id' => $otherUser->id,
|
|
'hosting_product_id' => $product->id,
|
|
'hosting_node_id' => $node->id,
|
|
'username' => 'otheracct',
|
|
'primary_domain' => 'other.example.com',
|
|
'type' => 'shared',
|
|
'status' => 'active',
|
|
'php_version' => '8.2',
|
|
]);
|
|
});
|
|
|
|
$site = HostedSite::create([
|
|
'hosting_account_id' => $otherAccount->id,
|
|
'domain' => 'linked-example.com',
|
|
'document_root' => '/home/otheracct/public_html/linked-example.com',
|
|
'type' => 'addon',
|
|
'status' => 'active',
|
|
]);
|
|
$site->delete();
|
|
|
|
$provider = \Mockery::mock(SharedNodeProvider::class);
|
|
$provider->shouldNotReceive('addSite');
|
|
$this->app->instance(SharedNodeProvider::class, $provider);
|
|
|
|
$session = $this->app['session.store'];
|
|
$session->start();
|
|
|
|
$request = Request::create('http://localhost/hosting/panel/' . $account->id . '/domains', 'POST', [
|
|
'domain' => 'linked-example.com',
|
|
], [], [], [
|
|
'HTTP_REFERER' => 'http://localhost/hosting/accounts/' . $account->id,
|
|
]);
|
|
$request->setUserResolver(fn (): User => $user);
|
|
$request->setLaravelSession($session);
|
|
|
|
$response = $this->app->make(HostingPanelController::class)->addDomain(
|
|
$request,
|
|
$account,
|
|
$this->app->make(DomainDnsBlueprintService::class),
|
|
$this->app->make(DomainVerificationService::class),
|
|
);
|
|
|
|
$this->assertSame(302, $response->getStatusCode());
|
|
$this->assertSame('This domain is already in use on another hosting account.', $session->get('error'));
|
|
$this->assertSoftDeleted('hosted_sites', [
|
|
'id' => $site->id,
|
|
'hosting_account_id' => $otherAccount->id,
|
|
'domain' => 'linked-example.com',
|
|
]);
|
|
}
|
|
}
|