Skip to content

Commit

Permalink
feat: #88 add the quotas page, ensure quotas for deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
bohdan-shulha committed Sep 13, 2024
1 parent 1e75e6c commit dce31ac
Show file tree
Hide file tree
Showing 19 changed files with 616 additions and 164 deletions.
12 changes: 12 additions & 0 deletions _ide_helper_actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ class InitCluster {}

namespace App\Actions\Services;

/**
* @method static \Lorisleiva\Actions\Decorators\JobDecorator|\Lorisleiva\Actions\Decorators\UniqueJobDecorator makeJob(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static \Lorisleiva\Actions\Decorators\UniqueJobDecorator makeUniqueJob(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static \Illuminate\Foundation\Bus\PendingDispatch dispatch(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static \Illuminate\Foundation\Bus\PendingDispatch|\Illuminate\Support\Fluent dispatchIf(bool $boolean, \App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static \Illuminate\Foundation\Bus\PendingDispatch|\Illuminate\Support\Fluent dispatchUnless(bool $boolean, \App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static dispatchSync(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static dispatchNow(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static dispatchAfterResponse(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
* @method static \App\Models\Service run(\App\Models\User $user, \App\Models\Team $team, string $name, \App\Models\DeploymentData $deploymentData)
*/
class CreateService {}
/**
* @method static \Lorisleiva\Actions\Decorators\JobDecorator|\Lorisleiva\Actions\Decorators\UniqueJobDecorator makeJob(\App\Models\User $user, \App\Models\Service $service, \App\Models\DeploymentData $deploymentData)
* @method static \Lorisleiva\Actions\Decorators\UniqueJobDecorator makeUniqueJob(\App\Models\User $user, \App\Models\Service $service, \App\Models\DeploymentData $deploymentData)
Expand Down
65 changes: 65 additions & 0 deletions app/Actions/Services/CreateService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace App\Actions\Services;

use App\Models\DeploymentData;
use App\Models\Service;
use App\Models\Team;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;

class CreateService
{
use AsAction;

public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'deploymentData' => ['required', 'array'],
];
}

public function authorize(ActionRequest $request): bool
{
return true; // Authorization will be handled by policies
}

public function handle(User $user, Team $team, string $name, DeploymentData $deploymentData): Service
{
return DB::transaction(function () use ($user, $team, $name, $deploymentData) {
$swarm = $team->swarms()->firstOrFail();

$service = new Service([
'name' => $name,
'team_id' => $team->id,
'swarm_id' => $swarm->id,
]);

$service->save();

StartDeployment::run($user, $service, $deploymentData);

return $service;
});
}

public function asController(ActionRequest $request)
{
$user = $request->user();
$team = $user->currentTeam;
$quotas = $team->quotas();

$quotas->services->ensureQuota();

$validated = $request->validated();
$deploymentData = DeploymentData::validateAndCreate($validated['deploymentData']);

$service = $this->handle($user, $team, $validated['name'], $deploymentData);

return redirect()->route('services.deployments', $service)
->with('success', 'Service created and deployment scheduled successfully.');
}
}
20 changes: 11 additions & 9 deletions app/Actions/Services/StartDeployment.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,20 @@
use Illuminate\Support\Facades\DB;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
use Symfony\Component\HttpFoundation\Response;

class StartDeployment
{
use AsAction;

public function rules(): array
{
return [
'service_id' => ['required', 'exists:services,id'],
'deployment_data' => ['required', DeploymentData::class],
];
return DeploymentData::getValidationRules([]);
}

public function authorize(ActionRequest $request): bool
{
$service = Service::with('team')->findOrFail($request->service_id);

return $request->user()->belongsToTeam($service->team);
return true;
}

public function handle(User $user, Service $service, DeploymentData $deploymentData): Deployment
Expand All @@ -52,11 +48,17 @@ public function handle(User $user, Service $service, DeploymentData $deploymentD
});
}

public function asController(ActionRequest $request)
public function asController(Service $service, ActionRequest $request): Response
{
$service = Service::findOrFail($request->service_id);
$deploymentData = DeploymentData::make($request->validated());

$team = $service->team;
$quotas = $team->quotas();

$quotas->deployments->ensureQuota();

$this->handle($request->user(), $service, $deploymentData);

return to_route('services.deployments', $service);
}
}
44 changes: 10 additions & 34 deletions app/Http/Controllers/ServiceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace App\Http\Controllers;

use App\Actions\Services\StartDeployment;
use App\Http\Requests\StoreServiceRequest;
use App\Http\Requests\UpdateServiceRequest;
use App\Models\DeploymentData;
use App\Models\Service;
Expand All @@ -26,7 +24,16 @@ public function index()

$swarmExists = Swarm::exists();

return Inertia::render('Services/Index', ['services' => $services, 'swarmExists' => $swarmExists]);
// Check if the quota is reached using ItemQuota
$team = auth()->user()->currentTeam;
$serviceQuota = $team->quotas()->services;
$quotaReached = $serviceQuota->quotaReached();

return Inertia::render('Services/Index', [
'services' => $services,
'swarmExists' => $swarmExists,
'quotaReached' => $quotaReached,
]);
}

/**
Expand Down Expand Up @@ -55,30 +62,6 @@ public function create()
]);
}

/**
* Store a newly created resource in storage.
*/
public function store(StoreServiceRequest $request)
{
$deploymentData = DeploymentData::validateAndCreate($request->get('deploymentData'));

$team = auth()->user()->currentTeam;
$swarm = $team->swarms()->firstOrFail();

$service = Service::make($request->validated());
$service->team_id = $team->id;
$service->swarm_id = $swarm->id;

DB::transaction(function () use ($service, $deploymentData) {
$service->save();

StartDeployment::run(auth()->user(), $service, $deploymentData);
});

return to_route('services.deployments', $service)
->with('success', 'Service created and deployment scheduled successfully.');
}

/**
* Display the specified resource.
*/
Expand Down Expand Up @@ -113,13 +96,6 @@ public function deployments(Service $service)
return Inertia::render('Services/Deployments', ['service' => $service]);
}

public function deploy(Service $service, DeploymentData $deploymentData)
{
StartDeployment::run(auth()->user(), $service, $deploymentData);

return to_route('services.deployments', $service);
}

/**
* Show the form for editing the specified resource.
*/
Expand Down
38 changes: 38 additions & 0 deletions app/Http/Controllers/TeamQuotasController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Http\Controllers;

use App\Models\Team;
use Inertia\Inertia;

class TeamQuotasController extends Controller
{
public function index(Team $team)
{
$quotas = $team->quotas();
$isOnTrial = $team->onTrial();
$quotaReached = false;

$formattedQuotas = [];
foreach ($quotas as $key => $quota) {
$formattedQuotas[$key] = [
'currentUsage' => $quota->currentUsage(),
'maxUsage' => $quota->maxUsage,
'isSoftQuota' => $quota->isSoftQuota,
'almostQuotaReached' => $quota->almostQuotaReached(),
'isIntrinsic' => $key === 'swarms', // Mark swarms as intrinsic
];

if ($quota->quotaReached() && ! $formattedQuotas[$key]['isIntrinsic']) {
$quotaReached = true;
}
}

return Inertia::render('Teams/Quotas', [
'team' => $team->only(['id', 'name']),
'quotas' => $formattedQuotas,
'isOnTrial' => $isOnTrial,
'quotaReached' => $quotaReached,
]);
}
}
10 changes: 7 additions & 3 deletions app/Models/PricingPlan/ItemQuota.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@
namespace App\Models\PricingPlan;

use Closure;
use RuntimeException;
use Illuminate\Validation\ValidationException;

class ItemQuota
{
public function __construct(
public string $name,
public int $maxUsage,
protected Closure $getCurrentUsage,
public bool $isSoftQuota = false
) {}

public function ensureQuota(): void
{
if ($this->quotaReached()) {
throw new RuntimeException('Invalid State - The team is at its node limit');
throw ValidationException::withMessages([
'quota' => "The maximum limit of {$this->maxUsage} {$this->name} has been reached.",
]);
}
}

Expand All @@ -29,7 +33,7 @@ public function quotaReached(): bool
return $this->currentUsage() >= $this->maxUsage;
}

protected function currentUsage(): int
public function currentUsage(): int
{
return call_user_func($this->getCurrentUsage);
}
Expand Down
17 changes: 17 additions & 0 deletions app/Models/PricingPlan/Plan.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Models\PricingPlan;

use Spatie\LaravelData\Data;

class Plan extends Data
{
public function __construct(
public string $name,
public int $price,
public string $description,
public ?string $product_id,
public ?string $price_id,
public array $quotas
) {}
}
2 changes: 2 additions & 0 deletions app/Models/PricingPlan/UsageQuotas.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ class UsageQuotas extends Data
public function __construct(
public ItemQuota $nodes,
public ItemQuota $swarms,
public ItemQuota $services,
public ItemQuota $deployments
) {}
}
Loading

0 comments on commit dce31ac

Please sign in to comment.