Skip to content

Commit

Permalink
Add backend support for Coterm
Browse files Browse the repository at this point in the history
  • Loading branch information
ericwang401 committed Nov 30, 2023
1 parent 8d14047 commit 95491e3
Show file tree
Hide file tree
Showing 17 changed files with 578 additions and 71 deletions.
81 changes: 78 additions & 3 deletions app/Http/Controllers/Admin/CotermController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,109 @@

namespace Convoy\Http\Controllers\Admin;

use Convoy\Http\Controllers\ApplicationApiController;
use Convoy\Http\Requests\Admin\Coterms\StoreCotermRequest;
use Convoy\Http\Requests\Admin\Coterms\UpdateAttachedNodesRequest;
use Convoy\Http\Requests\Admin\Coterms\UpdateCotermRequest;
use Convoy\Models\Coterm;
use Convoy\Models\Filters\FiltersCoterm;
use Convoy\Models\Filters\FiltersNode;
use Convoy\Services\Coterm\CotermTokenCreationService;
use Convoy\Transformers\Admin\CotermTransformer;
use Convoy\Transformers\Admin\NodeTransformer;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\QueryBuilder;

class CotermController
class CotermController extends ApplicationApiController
{
public function index()
public function __construct(private CotermTokenCreationService $cotermTokenCreator)
{

}

public function index(Request $request)
{
$addressPools = QueryBuilder::for(Coterm::query())
->withCount(['nodes'])
->defaultSort('-id')
->allowedFilters(
['name', AllowedFilter::custom(
'*', new FiltersCoterm(),
)],
)
->paginate(min($request->query('per_page', 50), 100))->appends(
$request->query(),
);

return fractal($addressPools, new CotermTransformer())->respond();
}

public function show(Coterm $coterm)
{
$coterm->loadCount(['nodes']);

return fractal($coterm, new CotermTransformer())->respond();
}

public function store(StoreCotermRequest $request)
{
$coterm = Coterm::create($request->safe()->except('node_ids'));
if ($request->node_ids !== null) {
$coterm->nodes()->attach($request->node_ids);
}
$coterm->loadCount(['nodes']);

return fractal($coterm, new CotermTransformer())->respond();
}

public function update(UpdateCotermRequest $request, Coterm $coterm)
{
$coterm->update($request->validated());
if ($request->node_ids !== null) {
$coterm->nodes()->sync($request->node_ids);
}
$coterm->loadCount(['nodes']);

return fractal($coterm, new CotermTransformer())->respond();
}

public function getAttachedNodes(Request $request, Coterm $coterm)
{
$nodes = QueryBuilder::for($coterm->nodes())
->withCount('servers')
->allowedFilters(
['name', 'fqdn', AllowedFilter::exact(
'location_id',
), AllowedFilter::custom('*', new FiltersNode())],
)
->paginate(min($request->query('per_page', 50), 100))->appends(
$request->query(),
);

return fractal($nodes, new NodeTransformer())->respond();
}

public function updateAttachedNodes(UpdateAttachedNodesRequest $request, Coterm $coterm)
{
$coterm->nodes()->sync($request->node_ids);
$coterm->loadCount(['nodes']);

return fractal($coterm, new CotermTransformer())->respond();
}

public function resetCotermToken(Coterm $coterm)
{
$creds = $this->cotermTokenCreator->handle();
$coterm->update([
'token_id' => $creds['token_id'],
'token' => $creds['token'],
]);

return fractal($coterm, new CotermTransformer())->parseIncludes('token')->respond();
}

public function destroy(Coterm $coterm)
{
return $this->returnNoContent();
}
}
14 changes: 14 additions & 0 deletions app/Http/Requests/Admin/Coterms/DeleteCotermRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Convoy\Http\Requests\Admin\Coterms;

use Convoy\Http\Requests\BaseApiRequest;
use Convoy\Models\Coterm;

class DeleteCotermRequest extends BaseApiRequest
{
public function authorize(): bool
{
return $this->user()->can('delete', $this->parameter('coterm', Coterm::class));
}
}
6 changes: 5 additions & 1 deletion app/Http/Requests/Admin/Coterms/StoreCotermRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ public function rules(): array
{
$rules = Coterm::getRules();

return Arr::only($rules, ['name', 'is_tls_enabled', 'fqdn', 'port']);
return [
...Arr::only($rules, ['name', 'is_tls_enabled', 'fqdn', 'port']),
'node_ids' => ['nullable', 'array'],
'node_ids.*' => ['required', 'integer', 'exists:nodes,id'],
];
}
}
6 changes: 5 additions & 1 deletion app/Http/Requests/Admin/Coterms/UpdateCotermRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public function rules(): array
$coterm = $this->parameter('coterm', Coterm::class);
$rules = Coterm::getRulesForUpdate($coterm);

return Arr::only($rules, ['name', 'is_tls_enabled', 'fqdn', 'port']);
return [
...Arr::only($rules, ['name', 'is_tls_enabled', 'fqdn', 'port']),
'node_ids' => ['nullable', 'array'],
'node_ids.*' => ['required', 'integer', 'exists:nodes,id'],
];
}
}
15 changes: 15 additions & 0 deletions app/Models/Filters/FiltersCoterm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Convoy\Models\Filters;

use Illuminate\Database\Eloquent\Builder;
use Spatie\QueryBuilder\Filters\Filter;

class FiltersCoterm implements Filter
{
public function __invoke(Builder $query, $value, string $property)
{
$query->where('id', $value)
->orWhereRaw('LOWER(name) LIKE ?', ["%$value%"]);
}
}
23 changes: 23 additions & 0 deletions app/Policies/CotermPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Convoy\Policies;

use Convoy\Models\Coterm;
use Convoy\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class CotermPolicy
{
use HandlesAuthorization;

public function delete(User $user, Coterm $coterm): bool
{
$coterm->loadCount(['nodes']);

if ($coterm->nodes_count > 0) {
$this->deny('Cannot delete an instance of Coterm with nodes attached to it.');
}

return true;
}
}
38 changes: 23 additions & 15 deletions app/Services/Coterm/CotermJWTService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,39 @@

namespace Convoy\Services\Coterm;

use Convoy\Models\User;
use Convoy\Models\Server;
use Carbon\CarbonImmutable;
use Webmozart\Assert\Assert;
use Lcobucci\JWT\Token\Plain;
use Convoy\Services\Api\JWTService;
use Convoy\Enums\Server\ConsoleType;
use Convoy\Models\Coterm;
use Convoy\Models\Server;
use Convoy\Models\User;
use Convoy\Services\Api\JWTService;
use Lcobucci\JWT\Token\Plain;
use Webmozart\Assert\Assert;

class CotermJWTService
{
public function __construct(private JWTService $JWTService) {}
public function __construct(private JWTService $JWTService)
{
}

public function handle(Server $server, User $user, ConsoleType $consoleType): Plain
{
Assert::notEmpty($server->node->coterm_fqdn, 'Coterm FQDN isn\'t defined. Is Coterm enabled?');
Assert::notEmpty($server->node->coterm_token, 'Coterm token isn\'t defined. Is Coterm enabled?');
Assert::isInstanceOf(
$server->node->coterm, Coterm::class,
'The server\'s node does not have a Coterm instance.',
);

$token = $this->JWTService
->setExpiresAt(CarbonImmutable::now()->addSeconds(30))
->setUser($user)
->setClaims([
'server_uuid' => $server->uuid,
'console_type' => $consoleType->value,
])
->handle($server->node->coterm_token, $server->node->getCotermConnectionAddress(), $user->uuid . $server->uuid);
->setExpiresAt(CarbonImmutable::now()->addSeconds(30))
->setUser($user)
->setClaims([
'server_uuid' => $server->uuid,
'console_type' => $consoleType->value,
])
->handle(
$server->node->coterm->token, $server->node->getCotermConnectionAddress(),
$user->uuid . $server->uuid,
);

return $token;
}
Expand Down
31 changes: 31 additions & 0 deletions app/Transformers/Admin/CotermTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Convoy\Transformers\Admin;

use Convoy\Models\Coterm;
use League\Fractal\TransformerAbstract;

class CotermTransformer extends TransformerAbstract
{
protected array $availableIncludes = ['token'];

public function transform(Coterm $coterm): array
{
return [
'id' => (int)$coterm->id,
'name' => $coterm->name,
'is_tls_enabled' => (boolean)$coterm->is_tls_enabled,
'fqdn' => $coterm->fqdn,
'port' => (int)$coterm->port,
'nodes_count' => (int)$coterm->nodes_count,
];
}

public function includeToken(Coterm $coterm): array
{
return [
'token_id' => $coterm->token_id,
'token' => $coterm->token,
];
}
}
32 changes: 32 additions & 0 deletions resources/scripts/api/admin/coterms/createCoterm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { rawDataToCoterm } from '@/api/admin/coterms/getCoterms'
import http from '@/api/http'

interface CreateCotermParameters {
name: string
isTlsEnabled: boolean
fqdn: string
port: number
nodeIds?: number[] | null
}

const createCoterm = async ({
name,
isTlsEnabled,
fqdn,
port,
nodeIds,
}: CreateCotermParameters) => {
const {
data: { data },
} = await http.post('/api/admin/coterms', {
name,
is_tls_enabled: isTlsEnabled,
fqdn,
port,
node_ids: nodeIds,
})

return rawDataToCoterm(data)
}

export default createCoterm
5 changes: 5 additions & 0 deletions resources/scripts/api/admin/coterms/deleteCoterm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import http from '@/api/http'

const deleteCoterm = (id: string) => http.delete(`/admin/coterms/${id}`)

export default deleteCoterm
33 changes: 33 additions & 0 deletions resources/scripts/api/admin/coterms/getAttachedNodes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { NodeResponse, rawDataToNode } from '@/api/admin/nodes/getNodes'
import http, { getPaginationSet } from '@/api/http'


export interface QueryParams {
query?: string | null
fqdn?: string | null
locationId?: number | null
page?: number | null
perPage?: number | null
}

const getAttachedNodes = async (
id: number,
{ query, fqdn, locationId, page, perPage = 50 }: QueryParams
): Promise<NodeResponse> => {
const { data } = await http.get(`/api/admin/coterms/${id}/nodes`, {
params: {
query,
fqdn,
location_id: locationId,
page,
per_page: perPage,
},
})

return {
items: data.data.map(rawDataToNode),
pagination: getPaginationSet(data.meta.pagination),
}
}

export default getAttachedNodes
Loading

0 comments on commit 95491e3

Please sign in to comment.