Skip to content
Open
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
22 changes: 19 additions & 3 deletions app/Classes/PterodactylClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,22 @@ public function createServer(Server $server, Egg $egg, int $allocationId, mixed
}
}

/**
* Get a server by external_id on Pterodactyl.
*
* @param string $externalId
* @return \Illuminate\Http\Client\Response
* @throws Exception
*/
public function getServerByExternalId(string $externalId)
{
try {
return $this->application->get("application/servers/external/{$externalId}");
} catch (Exception $e) {
throw self::getException('Failed to get server by external_id from pterodactyl - ' . $e->getMessage());
}
}

public function suspendServer(Server $server)
{
try {
Expand Down Expand Up @@ -407,7 +423,7 @@ public function getServerAttributes(int $pterodactylId, bool $deleteOn404 = fals
* @param Server $server
* @param Product $product
* @return Response
*
*
* @deprecated Use updateServerBuild instead.
*/
public function updateServer(Server $server, Product $product)
Expand All @@ -434,7 +450,7 @@ public function updateServer(Server $server, Product $product)
*
* @param Server $server
* @return Response
*
*
* @throws Exception
*/
public function updateServerBuild(string $pterodactylId, int $pterodactylAllocation, Product $product)
Expand Down Expand Up @@ -487,7 +503,7 @@ public function updateServerOwner(Server $server, int $userId)
* @param Server $server
* @param array $data
* @return Response
*
*
* @throws HttpException
* @throws Exception
*/
Expand Down
19 changes: 7 additions & 12 deletions app/Http/Controllers/Api/ServerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Http\Controllers\Api;

use App\Classes\PterodactylClient;
use App\Events\ServerCreatedEvent;
use App\Events\ServerDeletedEvent;
use App\Models\Product;
use App\Models\User;
Expand Down Expand Up @@ -68,7 +67,7 @@ public function index(Request $request)
* @param Request $request
* @param string $serverId
* @return ServerResource
*
*
* @throws ModelNotFoundException
*/
public function show(Request $request, string $serverId)
Expand All @@ -86,7 +85,7 @@ public function show(Request $request, string $serverId)
*
* @param Request $request
* @return ServerResource
*
*
* @throws ValidationException
*/
public function store(CreateServerRequest $request)
Expand All @@ -99,10 +98,6 @@ public function store(CreateServerRequest $request)
try {
$server = $this->serverCreationService->handle($user, $product, $data);

$user->decrement("credits", $product->price);

event(new ServerCreatedEvent($user, $server));

return ServerResource::make($server->fresh());
} catch (Exception $e) {
return response()->json([
Expand All @@ -117,7 +112,7 @@ public function store(CreateServerRequest $request)
* @param UpdateServerRequest $request
* @param Server $server
* @return ServerResource
*
*
* @throws ModelNotFoundException
* @throws Exception
*/
Expand Down Expand Up @@ -157,7 +152,7 @@ public function update(UpdateServerRequest $request, Server $server)
* @param UpdateServerBuildRequest $request
* @param Server $server
* @return ServerResource|JsonResponse
*
*
* @throws ModelNotFoundException
*/
public function updateBuild(UpdateServerBuildRequest $request, Server $server)
Expand All @@ -182,7 +177,7 @@ public function updateBuild(UpdateServerBuildRequest $request, Server $server)
* @param DeleteServerRequest $request
* @param Server $server
* @return \Illuminate\Http\Response
*
*
* @throws ModelNotFoundException
*/
public function destroy(DeleteServerRequest $request, Server $server)
Expand Down Expand Up @@ -214,7 +209,7 @@ public function destroy(DeleteServerRequest $request, Server $server)
* @param SuspendServerRequest $request
* @param Server $server
* @return ServerResource|JsonResponse
*
*
* @throws ModelNotFoundException
*/
public function suspend(SuspendServerRequest $request, Server $server)
Expand Down Expand Up @@ -244,7 +239,7 @@ public function suspend(SuspendServerRequest $request, Server $server)
* @param UnsuspendServerRequest $request
* @param Server $server
* @return ServerResource|JsonResponse
*
*
* @throws ModelNotFoundException
*/
public function unSuspend(UnsuspendServerRequest $request, Server $server)
Expand Down
112 changes: 43 additions & 69 deletions app/Http/Controllers/ServerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Carbon\Carbon;
use App\Settings\UserSettings;
use App\Settings\ServerSettings;
use App\Services\ServerCreationService;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Enums\BillingPriority;
Expand Down Expand Up @@ -51,20 +52,23 @@ class ServerController extends Controller
private ServerSettings $serverSettings;
private UserSettings $userSettings;
private DiscordSettings $discordSettings;
private ServerCreationService $serverCreationService;

public function __construct(
PterodactylSettings $pteroSettings,
GeneralSettings $generalSettings,
ServerSettings $serverSettings,
UserSettings $userSettings,
DiscordSettings $discordSettings
DiscordSettings $discordSettings,
ServerCreationService $serverCreationService
) {
$this->pteroSettings = $pteroSettings;
$this->pterodactyl = new PterodactylClient($pteroSettings);
$this->generalSettings = $generalSettings;
$this->serverSettings = $serverSettings;
$this->userSettings = $userSettings;
$this->discordSettings = $discordSettings;
$this->serverCreationService = $serverCreationService;
}

public function index(): \Illuminate\View\View
Expand Down Expand Up @@ -120,7 +124,10 @@ public function store(Request $request): RedirectResponse
Cache::put($lockKey, true, 5);

$validationResult = $this->validateServerCreation($request);
if ($validationResult) return $validationResult;
if ($validationResult) {
Cache::forget($lockKey);
return $validationResult;
}

$request->validate([
'name' => 'required|max:191',
Expand All @@ -131,17 +138,33 @@ public function store(Request $request): RedirectResponse
'billing_priority' => ['nullable', new Enum(BillingPriority::class)],
]);

$server = $this->createServer($request);
try {
$user = $request->user();
$product = Product::findOrFail($request->input('product'));

if (!$server) {
return redirect()->route('servers.index')
->with('error', __('Server creation failed'));
}
$server = $this->serverCreationService->handle($user, $product, [
'name' => $request->input('name'),
'egg_id' => $request->input('egg'),
'location_id' => $request->input('location'),
'billing_priority' => $request->input('billing_priority', $product->default_billing_priority),
'egg_variables' => $request->input('egg_variables'),
]);

Cache::forget($lockKey);

$this->handlePostCreation($request->user(), $server);
if (!$server) {
return redirect()->route('servers.index')
->with('error', __('Server creation failed'));
}

return redirect()->route('servers.index')
->with('success', __('Server created'));
return redirect()->route('servers.index')
->with('success', __('Server created'));
} catch (Exception $e) {
Cache::forget($lockKey);

return redirect()->route('servers.index')
->with('error', $e->getMessage());
}
}

private function validateServerCreation(Request $request): ?RedirectResponse
Expand Down Expand Up @@ -268,71 +291,22 @@ private function updateServerInfo(Server $server, array $serverInfo): void
}
}

/**
* @deprecated Once everyone is migrated to ServerCreationService.
*/
private function createServer(Request $request): ?Server
{
$product = Product::findOrFail($request->input('product'));
$egg = $product->eggs()->findOrFail($request->input('egg'));
$node = $this->findAvailableNode($request->input('location'), $product);

if (!$node) return null;

$server = $request->user()->servers()->create([
'name' => $request->input('name'),
'product_id' => $product->id,
'last_billed' => Carbon::now(),
'billing_priority' => $request->input('billing_priority', $product->default_billing_priority),
]);

$allocationId = $this->pterodactyl->getFreeAllocationId($node);
if (!$allocationId) {
Log::error('No AllocationID found.', [
'server_id' => $server->id,
'node_id' => $node->id,
]);
$server->delete();
return null;
}

$response = $this->pterodactyl->createServer($server, $egg, $allocationId, $request->input('egg_variables'));
if ($response->failed()) {
Log::error('Failed to create server on Pterodactyl', [
'server_id' => $server->id,
'status' => $response->status(),
'error' => $response->json()
]);
$server->delete();
return null;
}

$serverAttributes = $response->json()['attributes'];
$server->update([
'pterodactyl_id' => $serverAttributes['id'],
'identifier' => $serverAttributes['identifier']
]);

return $server;
// Legacy path; use ServerCreationService::handle() instead.
throw new \BadMethodCallException('createServer() is deprecated. Use ServerCreationService::handle().');
}

/**
* @deprecated Once everyone is migrated to ServerCreationService.
*/
private function handlePostCreation(User $user, Server $server): void
{
logger('Product Price: ' . $server->product->price);

$user->decrement('credits', $server->product->price);
Cache::forget('user_credits_left:' . $user->id);

try {
if ($this->discordSettings->role_for_active_clients &&
$user->discordUser &&
$user->servers->count() >= 1
) {
$user->discordUser->addOrRemoveRole(
'add',
$this->discordSettings->role_id_for_active_clients
);
}
} catch (Exception $e) {
Log::debug('Discord role update failed: ' . $e->getMessage());
}
// Legacy path; use PostServerCreationJob for idempotent async processing.
throw new \BadMethodCallException('handlePostCreation() is deprecated. Use PostServerCreationJob instead.');
}

public function destroy(Server $server): RedirectResponse
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/ServerResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function toArray(Request $request): array
'created_at' => $this->created_at->toDateTimeString(),
'updated_at' => $this->updated_at->toDateTimeString(),
'last_billed' => $this->last_billed->toDateTimeString(),
'status' => $this->status,
'product_count' => $this->whenCounted('product'),
'product_exists' => $this->whenExistsLoaded('product'),
'product' => ProductResource::make($this->whenLoaded('product')),
Expand Down
39 changes: 39 additions & 0 deletions app/Jobs/PostServerCreationJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\Jobs;

use App\Events\ServerCreatedEvent;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class PostServerCreationJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public string $serverId;

public function __construct(string $serverId)
{
$this->serverId = $serverId;
$this->queue = 'default';
}

public function handle(): void
{
$server = Server::with('user')->find($this->serverId);

if (!$server || $server->status !== Server::STATUS_ACTIVE) {
return;
}

if (!$server->user) {
return;
}

event(new ServerCreatedEvent($server->user, $server));
}
}
Loading