diff --git a/website/app/Http/Controllers/Account/DashboardController.php b/website/app/Http/Controllers/Account/DashboardController.php index 24caad2..f6b36f3 100644 --- a/website/app/Http/Controllers/Account/DashboardController.php +++ b/website/app/Http/Controllers/Account/DashboardController.php @@ -15,9 +15,40 @@ class DashboardController extends Controller { $user = $request->user(); + $activeServicesCount = $user->services() + ->where('status', 'active') + ->count(); + + $activeSubscriptions = $user->subscriptions() + ->with('plan') + ->whereIn('stripe_status', ['active', 'trialing']) + ->latest() + ->get(); + + $activeSubscriptionsCount = $activeSubscriptions->count(); + + $latestInvoices = $user->invoices() + ->latest() + ->limit(5) + ->get(); + + $pendingInvoicesAmount = $user->invoices() + ->whereIn('status', ['pending', 'overdue']) + ->sum('total'); + + $nextRenewalDate = $user->subscriptions() + ->whereIn('stripe_status', ['active', 'trialing']) + ->whereNotNull('current_period_end') + ->orderBy('current_period_end') + ->value('current_period_end'); + return Inertia::render('Dashboard', [ - 'servicesCount' => $user->services()->count(), - 'activeServicesCount' => $user->services()->where('status', 'active')->count(), + 'activeServicesCount' => $activeServicesCount, + 'activeSubscriptionsCount' => $activeSubscriptionsCount, + 'activeSubscriptions' => $activeSubscriptions, + 'latestInvoices' => $latestInvoices, + 'pendingInvoicesAmount' => number_format((float) $pendingInvoicesAmount, 2, '.', ''), + 'nextRenewalDate' => $nextRenewalDate, ]); } } diff --git a/website/app/Providers/AppServiceProvider.php b/website/app/Providers/AppServiceProvider.php index 9c7325c..5794b9b 100644 --- a/website/app/Providers/AppServiceProvider.php +++ b/website/app/Providers/AppServiceProvider.php @@ -7,6 +7,7 @@ namespace App\Providers; use App\Http\Responses\LoginResponse; use App\Http\Responses\RegisterResponse; use App\Services\Billing\BillingServiceFactory; +use App\Services\Provisioning\ProvisioningFactory; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; use Illuminate\Support\Facades\RateLimiter; @@ -22,6 +23,7 @@ class AppServiceProvider extends ServiceProvider $this->app->singleton(LoginResponseContract::class, LoginResponse::class); $this->app->singleton(RegisterResponseContract::class, RegisterResponse::class); $this->app->singleton(BillingServiceFactory::class); + $this->app->singleton(ProvisioningFactory::class); } public function boot(): void diff --git a/website/app/Services/Provisioning/EnhanceService.php b/website/app/Services/Provisioning/EnhanceService.php new file mode 100644 index 0000000..f258eca --- /dev/null +++ b/website/app/Services/Provisioning/EnhanceService.php @@ -0,0 +1,298 @@ +baseUrl = rtrim(config('services.enhance.url', ''), '/'); + $this->token = config('services.enhance.token', ''); + } + + public function provision(Subscription $subscription): Service + { + $plan = $subscription->plan; + $user = $subscription->user; + + if (! $plan) { + throw new RuntimeException('Subscription has no associated plan.'); + } + + $service = Service::create([ + 'user_id' => $user->id, + 'subscription_id' => $subscription->id, + 'plan_id' => $plan->id, + 'service_type' => 'hosting', + 'platform' => 'enhance', + 'status' => 'pending', + ]); + + $this->logAction($service, 'provision', 'pending'); + + try { + $response = $this->client()->post('/api/v1/websites', [ + 'plan_id' => $plan->features['enhance_plan_id'] ?? null, + 'domain' => $plan->features['default_domain'] ?? 'hosting.ezscale.cloud', + 'customer_email' => $user->email, + ]); + + if (! $response->successful()) { + $this->logAction($service, 'provision', 'failed', $response->json(), $response->body()); + + throw new RuntimeException("Enhance provisioning failed: {$response->body()}"); + } + + $data = $response->json(); + $websiteId = (string) ($data['data']['id'] ?? $data['id'] ?? ''); + + $service->update([ + 'platform_service_id' => $websiteId, + 'status' => 'active', + 'domain' => $data['data']['domain'] ?? $data['domain'] ?? null, + 'ipv4_address' => $data['data']['ip_address'] ?? $data['ip_address'] ?? null, + 'provisioned_at' => now(), + ]); + + $this->logAction($service, 'provision', 'success', $data); + + return $service->fresh(); + } catch (RuntimeException $e) { + throw $e; + } catch (\Exception $e) { + $this->logAction($service, 'provision', 'failed', errorMessage: $e->getMessage()); + + $service->update(['status' => 'failed']); + + throw new RuntimeException("Enhance provisioning error: {$e->getMessage()}", 0, $e); + } + } + + public function suspend(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'suspend', 'pending'); + + try { + $response = $this->client()->post("/api/v1/websites/{$service->platform_service_id}/suspend"); + + if (! $response->successful()) { + $this->logAction($service, 'suspend', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'suspended', + 'suspended_at' => now(), + ]); + + $this->logAction($service, 'suspend', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('Enhance suspend failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'suspend', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + public function unsuspend(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'unsuspend', 'pending'); + + try { + $response = $this->client()->post("/api/v1/websites/{$service->platform_service_id}/unsuspend"); + + if (! $response->successful()) { + $this->logAction($service, 'unsuspend', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'active', + 'suspended_at' => null, + ]); + + $this->logAction($service, 'unsuspend', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('Enhance unsuspend failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'unsuspend', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + public function terminate(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'terminate', 'pending'); + + try { + $response = $this->client()->delete("/api/v1/websites/{$service->platform_service_id}"); + + if (! $response->successful()) { + $this->logAction($service, 'terminate', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'terminated', + 'terminated_at' => now(), + ]); + + $this->logAction($service, 'terminate', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('Enhance terminate failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'terminate', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + /** + * @return array{status: string, ip_address?: string, hostname?: string, platform_data?: array} + */ + public function getStatus(Service $service): array + { + $this->validateServicePlatform($service); + + try { + $response = $this->client()->get("/api/v1/websites/{$service->platform_service_id}"); + + if (! $response->successful()) { + return ['status' => 'unknown']; + } + + $data = $response->json(); + $websiteData = $data['data'] ?? $data; + + return [ + 'status' => $websiteData['status'] ?? 'unknown', + 'ip_address' => $websiteData['ip_address'] ?? $service->ipv4_address, + 'hostname' => $websiteData['domain'] ?? $service->domain, + 'platform_data' => $websiteData, + ]; + } catch (\Exception $e) { + Log::error('Enhance getStatus failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + return ['status' => 'unknown']; + } + } + + /** + * @return array{username?: string, password?: string, url?: string, additional?: array} + */ + public function getCredentials(Service $service): array + { + $this->validateServicePlatform($service); + + $stored = $service->credentials ?? []; + + try { + $response = $this->client()->get("/api/v1/websites/{$service->platform_service_id}"); + + if ($response->successful()) { + $data = $response->json(); + $websiteData = $data['data'] ?? $data; + + return [ + 'username' => $stored['username'] ?? null, + 'password' => $stored['password'] ?? null, + 'url' => $websiteData['control_panel_url'] ?? null, + 'additional' => [ + 'domain' => $websiteData['domain'] ?? $service->domain, + 'ip_address' => $websiteData['ip_address'] ?? $service->ipv4_address, + 'nameservers' => $websiteData['nameservers'] ?? [], + ], + ]; + } + } catch (\Exception $e) { + Log::error('Enhance getCredentials failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + } + + return [ + 'username' => $stored['username'] ?? null, + 'password' => $stored['password'] ?? null, + ]; + } + + private function client(): PendingRequest + { + return Http::withToken($this->token) + ->baseUrl($this->baseUrl) + ->acceptJson() + ->timeout(30); + } + + private function validateServicePlatform(Service $service): void + { + if (! $service->platform_service_id) { + throw new RuntimeException('Service has no platform service ID.'); + } + } + + /** + * @param array|null $response + */ + private function logAction( + Service $service, + string $action, + string $status, + ?array $response = null, + ?string $errorMessage = null, + ): void { + ProvisioningLog::create([ + 'service_id' => $service->id, + 'user_id' => $service->user_id, + 'action' => $action, + 'platform' => 'enhance', + 'platform_response' => $response, + 'status' => $status, + 'error_message' => $errorMessage, + ]); + } +} diff --git a/website/app/Services/Provisioning/ProvisioningFactory.php b/website/app/Services/Provisioning/ProvisioningFactory.php new file mode 100644 index 0000000..0c4e90d --- /dev/null +++ b/website/app/Services/Provisioning/ProvisioningFactory.php @@ -0,0 +1,23 @@ + app(VirtFusionService::class), + 'dedicated' => app(SynergyCPService::class), + 'hosting' => app(EnhanceService::class), + default => throw new InvalidArgumentException("Unsupported service type: {$serviceType}"), + }; + } +} diff --git a/website/app/Services/Provisioning/ProvisioningServiceInterface.php b/website/app/Services/Provisioning/ProvisioningServiceInterface.php new file mode 100644 index 0000000..aa10c6b --- /dev/null +++ b/website/app/Services/Provisioning/ProvisioningServiceInterface.php @@ -0,0 +1,45 @@ +} + */ + public function getStatus(Service $service): array; + + /** + * Get the access credentials for a service. + * + * @return array{username?: string, password?: string, url?: string, additional?: array} + */ + public function getCredentials(Service $service): array; +} diff --git a/website/app/Services/Provisioning/SynergyCPService.php b/website/app/Services/Provisioning/SynergyCPService.php new file mode 100644 index 0000000..a733ad3 --- /dev/null +++ b/website/app/Services/Provisioning/SynergyCPService.php @@ -0,0 +1,298 @@ +baseUrl = rtrim(config('services.synergycp.url', ''), '/'); + $this->token = config('services.synergycp.token', ''); + } + + public function provision(Subscription $subscription): Service + { + $plan = $subscription->plan; + $user = $subscription->user; + + if (! $plan) { + throw new RuntimeException('Subscription has no associated plan.'); + } + + $service = Service::create([ + 'user_id' => $user->id, + 'subscription_id' => $subscription->id, + 'plan_id' => $plan->id, + 'service_type' => 'dedicated', + 'platform' => 'synergycp', + 'status' => 'pending', + ]); + + $this->logAction($service, 'provision', 'pending'); + + try { + $response = $this->client()->post('/api/v1/servers', [ + 'plan_id' => $plan->features['synergycp_plan_id'] ?? null, + 'client_email' => $user->email, + 'hostname' => $plan->features['default_hostname'] ?? 'dedicated.ezscale.cloud', + ]); + + if (! $response->successful()) { + $this->logAction($service, 'provision', 'failed', $response->json(), $response->body()); + + throw new RuntimeException("SynergyCP provisioning failed: {$response->body()}"); + } + + $data = $response->json(); + $serverId = (string) ($data['data']['id'] ?? $data['id'] ?? ''); + + $service->update([ + 'platform_service_id' => $serverId, + 'status' => 'active', + 'ipv4_address' => $data['data']['ip_address'] ?? $data['ip_address'] ?? null, + 'hostname' => $data['data']['hostname'] ?? $data['hostname'] ?? null, + 'provisioned_at' => now(), + ]); + + $this->logAction($service, 'provision', 'success', $data); + + return $service->fresh(); + } catch (RuntimeException $e) { + throw $e; + } catch (\Exception $e) { + $this->logAction($service, 'provision', 'failed', errorMessage: $e->getMessage()); + + $service->update(['status' => 'failed']); + + throw new RuntimeException("SynergyCP provisioning error: {$e->getMessage()}", 0, $e); + } + } + + public function suspend(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'suspend', 'pending'); + + try { + $response = $this->client()->post("/api/v1/servers/{$service->platform_service_id}/suspend"); + + if (! $response->successful()) { + $this->logAction($service, 'suspend', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'suspended', + 'suspended_at' => now(), + ]); + + $this->logAction($service, 'suspend', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('SynergyCP suspend failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'suspend', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + public function unsuspend(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'unsuspend', 'pending'); + + try { + $response = $this->client()->post("/api/v1/servers/{$service->platform_service_id}/unsuspend"); + + if (! $response->successful()) { + $this->logAction($service, 'unsuspend', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'active', + 'suspended_at' => null, + ]); + + $this->logAction($service, 'unsuspend', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('SynergyCP unsuspend failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'unsuspend', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + public function terminate(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'terminate', 'pending'); + + try { + $response = $this->client()->delete("/api/v1/servers/{$service->platform_service_id}"); + + if (! $response->successful()) { + $this->logAction($service, 'terminate', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'terminated', + 'terminated_at' => now(), + ]); + + $this->logAction($service, 'terminate', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('SynergyCP terminate failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'terminate', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + /** + * @return array{status: string, ip_address?: string, hostname?: string, platform_data?: array} + */ + public function getStatus(Service $service): array + { + $this->validateServicePlatform($service); + + try { + $response = $this->client()->get("/api/v1/servers/{$service->platform_service_id}"); + + if (! $response->successful()) { + return ['status' => 'unknown']; + } + + $data = $response->json(); + $serverData = $data['data'] ?? $data; + + return [ + 'status' => $serverData['status'] ?? 'unknown', + 'ip_address' => $serverData['ip_address'] ?? $service->ipv4_address, + 'hostname' => $serverData['hostname'] ?? $service->hostname, + 'platform_data' => $serverData, + ]; + } catch (\Exception $e) { + Log::error('SynergyCP getStatus failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + return ['status' => 'unknown']; + } + } + + /** + * @return array{username?: string, password?: string, url?: string, additional?: array} + */ + public function getCredentials(Service $service): array + { + $this->validateServicePlatform($service); + + $stored = $service->credentials ?? []; + + try { + $response = $this->client()->get("/api/v1/servers/{$service->platform_service_id}"); + + if ($response->successful()) { + $data = $response->json(); + $serverData = $data['data'] ?? $data; + + return [ + 'username' => $stored['username'] ?? 'root', + 'password' => $stored['password'] ?? null, + 'url' => $serverData['ipmi_url'] ?? null, + 'additional' => [ + 'ip_address' => $serverData['ip_address'] ?? $service->ipv4_address, + 'hostname' => $serverData['hostname'] ?? $service->hostname, + 'ipmi_ip' => $serverData['ipmi_ip'] ?? null, + ], + ]; + } + } catch (\Exception $e) { + Log::error('SynergyCP getCredentials failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + } + + return [ + 'username' => $stored['username'] ?? 'root', + 'password' => $stored['password'] ?? null, + ]; + } + + private function client(): PendingRequest + { + return Http::withToken($this->token) + ->baseUrl($this->baseUrl) + ->acceptJson() + ->timeout(30); + } + + private function validateServicePlatform(Service $service): void + { + if (! $service->platform_service_id) { + throw new RuntimeException('Service has no platform service ID.'); + } + } + + /** + * @param array|null $response + */ + private function logAction( + Service $service, + string $action, + string $status, + ?array $response = null, + ?string $errorMessage = null, + ): void { + ProvisioningLog::create([ + 'service_id' => $service->id, + 'user_id' => $service->user_id, + 'action' => $action, + 'platform' => 'synergycp', + 'platform_response' => $response, + 'status' => $status, + 'error_message' => $errorMessage, + ]); + } +} diff --git a/website/app/Services/Provisioning/VirtFusionService.php b/website/app/Services/Provisioning/VirtFusionService.php new file mode 100644 index 0000000..c17c0a4 --- /dev/null +++ b/website/app/Services/Provisioning/VirtFusionService.php @@ -0,0 +1,297 @@ +baseUrl = rtrim(config('services.virtfusion.url', ''), '/'); + $this->token = config('services.virtfusion.token', ''); + } + + public function provision(Subscription $subscription): Service + { + $plan = $subscription->plan; + $user = $subscription->user; + + if (! $plan) { + throw new RuntimeException('Subscription has no associated plan.'); + } + + $service = Service::create([ + 'user_id' => $user->id, + 'subscription_id' => $subscription->id, + 'plan_id' => $plan->id, + 'service_type' => 'vps', + 'platform' => 'virtfusion', + 'status' => 'pending', + ]); + + $this->logAction($service, 'provision', 'pending'); + + try { + $response = $this->client()->post('/api/v1/servers', [ + 'package_id' => $plan->features['virtfusion_package_id'] ?? null, + 'user_email' => $user->email, + 'hostname' => $plan->features['default_hostname'] ?? 'server.ezscale.cloud', + ]); + + if (! $response->successful()) { + $this->logAction($service, 'provision', 'failed', $response->json(), $response->body()); + + throw new RuntimeException("VirtFusion provisioning failed: {$response->body()}"); + } + + $data = $response->json(); + $serverId = (string) ($data['data']['id'] ?? $data['id'] ?? ''); + + $service->update([ + 'platform_service_id' => $serverId, + 'status' => 'active', + 'ipv4_address' => $data['data']['ip_address'] ?? $data['ip_address'] ?? null, + 'hostname' => $data['data']['hostname'] ?? $data['hostname'] ?? null, + 'provisioned_at' => now(), + ]); + + $this->logAction($service, 'provision', 'success', $data); + + return $service->fresh(); + } catch (RuntimeException $e) { + throw $e; + } catch (\Exception $e) { + $this->logAction($service, 'provision', 'failed', errorMessage: $e->getMessage()); + + $service->update(['status' => 'failed']); + + throw new RuntimeException("VirtFusion provisioning error: {$e->getMessage()}", 0, $e); + } + } + + public function suspend(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'suspend', 'pending'); + + try { + $response = $this->client()->post("/api/v1/servers/{$service->platform_service_id}/suspend"); + + if (! $response->successful()) { + $this->logAction($service, 'suspend', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'suspended', + 'suspended_at' => now(), + ]); + + $this->logAction($service, 'suspend', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('VirtFusion suspend failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'suspend', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + public function unsuspend(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'unsuspend', 'pending'); + + try { + $response = $this->client()->post("/api/v1/servers/{$service->platform_service_id}/unsuspend"); + + if (! $response->successful()) { + $this->logAction($service, 'unsuspend', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'active', + 'suspended_at' => null, + ]); + + $this->logAction($service, 'unsuspend', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('VirtFusion unsuspend failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'unsuspend', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + public function terminate(Service $service): bool + { + $this->validateServicePlatform($service); + + $this->logAction($service, 'terminate', 'pending'); + + try { + $response = $this->client()->delete("/api/v1/servers/{$service->platform_service_id}"); + + if (! $response->successful()) { + $this->logAction($service, 'terminate', 'failed', $response->json(), $response->body()); + + return false; + } + + $service->update([ + 'status' => 'terminated', + 'terminated_at' => now(), + ]); + + $this->logAction($service, 'terminate', 'success', $response->json()); + + return true; + } catch (\Exception $e) { + Log::error('VirtFusion terminate failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + $this->logAction($service, 'terminate', 'failed', errorMessage: $e->getMessage()); + + return false; + } + } + + /** + * @return array{status: string, ip_address?: string, hostname?: string, platform_data?: array} + */ + public function getStatus(Service $service): array + { + $this->validateServicePlatform($service); + + try { + $response = $this->client()->get("/api/v1/servers/{$service->platform_service_id}"); + + if (! $response->successful()) { + return ['status' => 'unknown']; + } + + $data = $response->json(); + $serverData = $data['data'] ?? $data; + + return [ + 'status' => $serverData['status'] ?? 'unknown', + 'ip_address' => $serverData['ip_address'] ?? $service->ipv4_address, + 'hostname' => $serverData['hostname'] ?? $service->hostname, + 'platform_data' => $serverData, + ]; + } catch (\Exception $e) { + Log::error('VirtFusion getStatus failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + + return ['status' => 'unknown']; + } + } + + /** + * @return array{username?: string, password?: string, url?: string, additional?: array} + */ + public function getCredentials(Service $service): array + { + $this->validateServicePlatform($service); + + $stored = $service->credentials ?? []; + + try { + $response = $this->client()->get("/api/v1/servers/{$service->platform_service_id}"); + + if ($response->successful()) { + $data = $response->json(); + $serverData = $data['data'] ?? $data; + + return [ + 'username' => $stored['username'] ?? 'root', + 'password' => $stored['password'] ?? null, + 'url' => $serverData['vnc_url'] ?? null, + 'additional' => [ + 'ip_address' => $serverData['ip_address'] ?? $service->ipv4_address, + 'hostname' => $serverData['hostname'] ?? $service->hostname, + ], + ]; + } + } catch (\Exception $e) { + Log::error('VirtFusion getCredentials failed', [ + 'service_id' => $service->id, + 'error' => $e->getMessage(), + ]); + } + + return [ + 'username' => $stored['username'] ?? 'root', + 'password' => $stored['password'] ?? null, + ]; + } + + private function client(): PendingRequest + { + return Http::withToken($this->token) + ->baseUrl($this->baseUrl) + ->acceptJson() + ->timeout(30); + } + + private function validateServicePlatform(Service $service): void + { + if (! $service->platform_service_id) { + throw new RuntimeException('Service has no platform service ID.'); + } + } + + /** + * @param array|null $response + */ + private function logAction( + Service $service, + string $action, + string $status, + ?array $response = null, + ?string $errorMessage = null, + ): void { + ProvisioningLog::create([ + 'service_id' => $service->id, + 'user_id' => $service->user_id, + 'action' => $action, + 'platform' => 'virtfusion', + 'platform_response' => $response, + 'status' => $status, + 'error_message' => $errorMessage, + ]); + } +} diff --git a/website/config/services.php b/website/config/services.php index 532acb9..c3afbfc 100644 --- a/website/config/services.php +++ b/website/config/services.php @@ -35,4 +35,19 @@ return [ ], ], + 'virtfusion' => [ + 'url' => env('VIRTFUSION_API_URL'), + 'token' => env('VIRTFUSION_API_TOKEN'), + ], + + 'synergycp' => [ + 'url' => env('SYNERGYCP_API_URL'), + 'token' => env('SYNERGYCP_API_TOKEN'), + ], + + 'enhance' => [ + 'url' => env('ENHANCE_API_URL'), + 'token' => env('ENHANCE_API_TOKEN'), + ], + ]; diff --git a/website/resources/ts/Pages/Dashboard.vue b/website/resources/ts/Pages/Dashboard.vue index 5e396df..040f2ab 100644 --- a/website/resources/ts/Pages/Dashboard.vue +++ b/website/resources/ts/Pages/Dashboard.vue @@ -1,69 +1,405 @@