132 lines
4.2 KiB
PHP
132 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Helpers\ResponseHelper;
|
|
use App\Models\PersonalAccessToken;
|
|
use App\Models\User;
|
|
use App\Support\TokenAbilities;
|
|
use Hypervel\Http\Request;
|
|
use Hypervel\Support\Facades\Auth;
|
|
|
|
class ApiTokenController
|
|
{
|
|
public function catalog()
|
|
{
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'abilities' => TokenAbilities::catalog(),
|
|
'wildcard' => TokenAbilities::WILDCARD,
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$tokens = PersonalAccessToken::query()
|
|
->where('tokenable_type', User::class)
|
|
->orderByDesc('id')
|
|
->get()
|
|
->map(fn ($t) => $this->present($t));
|
|
|
|
return response()->json(['success' => true, 'data' => $tokens]);
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:120',
|
|
'description' => 'nullable|string|max:500',
|
|
'abilities' => 'required|array|min:1',
|
|
'abilities.*' => 'string',
|
|
'allowed_ips' => 'nullable|array',
|
|
'allowed_ips.*' => 'string',
|
|
'expires_at' => 'nullable|date',
|
|
'tokenable_user_id' => 'nullable|integer',
|
|
]);
|
|
|
|
foreach ($validated['abilities'] as $ability) {
|
|
if (! TokenAbilities::exists($ability)) {
|
|
return ResponseHelper::returnError("Unknown ability: {$ability}", 422);
|
|
}
|
|
}
|
|
|
|
$owner = Auth::user();
|
|
$tokenable = $owner;
|
|
if (! empty($validated['tokenable_user_id'])) {
|
|
$tokenable = User::query()->find($validated['tokenable_user_id']);
|
|
if (! $tokenable) {
|
|
return ResponseHelper::returnError('Target user not found.', 404);
|
|
}
|
|
}
|
|
|
|
$result = $tokenable->createToken(
|
|
name: $validated['name'],
|
|
abilities: $validated['abilities'],
|
|
allowedIps: $validated['allowed_ips'] ?? null,
|
|
expiresAt: !empty($validated['expires_at']) ? new \DateTimeImmutable($validated['expires_at']) : null,
|
|
description: $validated['description'] ?? null,
|
|
createdBy: $owner->id,
|
|
);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'token' => $this->present($result['token']),
|
|
'plain_text_token' => $result['plainTextToken'],
|
|
],
|
|
'message' => 'Token created. Copy it now — it will not be shown again.',
|
|
]);
|
|
}
|
|
|
|
public function revoke(Request $request, int $id)
|
|
{
|
|
$token = PersonalAccessToken::query()->find($id);
|
|
if (! $token) {
|
|
return ResponseHelper::returnError('Token not found.', 404);
|
|
}
|
|
if ($token->revoked_at !== null) {
|
|
return ResponseHelper::returnError('Token already revoked.', 422);
|
|
}
|
|
$token->forceFill([
|
|
'revoked_at' => now(),
|
|
'revoked_by' => Auth::id(),
|
|
])->save();
|
|
|
|
return response()->json(['success' => true, 'data' => $this->present($token)]);
|
|
}
|
|
|
|
public function destroy(Request $request, int $id)
|
|
{
|
|
$token = PersonalAccessToken::query()->find($id);
|
|
if (! $token) {
|
|
return ResponseHelper::returnError('Token not found.', 404);
|
|
}
|
|
$token->delete();
|
|
return response()->json(['success' => true]);
|
|
}
|
|
|
|
private function present(PersonalAccessToken $t): array
|
|
{
|
|
return [
|
|
'id' => $t->id,
|
|
'name' => $t->name,
|
|
'description' => $t->description,
|
|
'tokenable_id' => $t->tokenable_id,
|
|
'tokenable_type' => $t->tokenable_type,
|
|
'abilities' => $t->abilities ?? [],
|
|
'allowed_ips' => $t->allowed_ips ?? [],
|
|
'expires_at' => $t->expires_at,
|
|
'last_used_at' => $t->last_used_at,
|
|
'last_used_ip' => $t->last_used_ip,
|
|
'revoked_at' => $t->revoked_at,
|
|
'created_by' => $t->created_by,
|
|
'created_at' => $t->created_at,
|
|
'is_active' => $t->isActive(),
|
|
];
|
|
}
|
|
}
|