- Any-LLM Gateway setup with Docker Compose - Laravel 11 admin interface with Livewire - Dashboard with usage statistics and charts - Gateway Users management with budget tracking - API Keys management with revocation - Budget templates with assignment - Usage Logs with filtering and CSV export - Model Pricing management with calculator - PostgreSQL database integration - Complete authentication system for admins
243 lines
7.3 KiB
PHP
243 lines
7.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\GatewayUser;
|
|
use App\Models\Budget;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Str;
|
|
|
|
class GatewayUserController extends Controller
|
|
{
|
|
/**
|
|
* Display a listing of the gateway users.
|
|
*/
|
|
public function index(Request $request)
|
|
{
|
|
$query = GatewayUser::with('budget')
|
|
->withCount(['apiKeys', 'usageLogs']);
|
|
|
|
// Search
|
|
if ($request->filled('search')) {
|
|
$search = $request->search;
|
|
$query->where(function ($q) use ($search) {
|
|
$q->where('user_id', 'like', "%{$search}%")
|
|
->orWhere('alias', 'like', "%{$search}%");
|
|
});
|
|
}
|
|
|
|
// Filter by status
|
|
if ($request->filled('status')) {
|
|
if ($request->status === 'active') {
|
|
$query->active();
|
|
} elseif ($request->status === 'blocked') {
|
|
$query->blocked();
|
|
}
|
|
}
|
|
|
|
// Sort
|
|
$sortField = $request->get('sort', 'created_at');
|
|
$sortDirection = $request->get('direction', 'desc');
|
|
$query->orderBy($sortField, $sortDirection);
|
|
|
|
$users = $query->paginate(20)->withQueryString();
|
|
|
|
return view('gateway-users.index', compact('users'));
|
|
}
|
|
|
|
/**
|
|
* Show the form for creating a new gateway user.
|
|
*/
|
|
public function create()
|
|
{
|
|
$budgets = Budget::all();
|
|
return view('gateway-users.create', compact('budgets'));
|
|
}
|
|
|
|
/**
|
|
* Store a newly created gateway user in storage.
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'alias' => 'nullable|string|max:255',
|
|
'budget_id' => 'nullable|exists:budgets,budget_id',
|
|
'metadata' => 'nullable|array',
|
|
]);
|
|
|
|
// Generate unique user_id
|
|
$userId = 'user_' . Str::random(16);
|
|
|
|
$user = GatewayUser::create([
|
|
'user_id' => $userId,
|
|
'alias' => $validated['alias'] ?? null,
|
|
'budget_id' => $validated['budget_id'] ?? null,
|
|
'spend' => 0,
|
|
'blocked' => false,
|
|
'metadata' => $validated['metadata'] ?? [],
|
|
]);
|
|
|
|
return redirect()
|
|
->route('gateway-users.show', $user->user_id)
|
|
->with('success', 'Gateway User created successfully!');
|
|
}
|
|
|
|
/**
|
|
* Display the specified gateway user.
|
|
*/
|
|
public function show(string $userId)
|
|
{
|
|
$user = GatewayUser::with(['apiKeys', 'budget'])
|
|
->findOrFail($userId);
|
|
|
|
// Get usage statistics for last 30 days
|
|
$stats = $this->getUserStatistics($userId, 30);
|
|
|
|
// Get recent logs
|
|
$recentLogs = $user->usageLogs()
|
|
->with('apiKey')
|
|
->orderByDesc('timestamp')
|
|
->limit(50)
|
|
->get();
|
|
|
|
// Get daily usage for chart (last 30 days)
|
|
$dailyUsage = $user->usageLogs()
|
|
->selectRaw('DATE(timestamp) as date, COUNT(*) as requests, SUM(cost) as cost, SUM(total_tokens) as tokens')
|
|
->where('timestamp', '>=', now()->subDays(30))
|
|
->groupBy('date')
|
|
->orderBy('date')
|
|
->get();
|
|
|
|
return view('gateway-users.show', compact('user', 'stats', 'recentLogs', 'dailyUsage'));
|
|
}
|
|
|
|
/**
|
|
* Show the form for editing the specified gateway user.
|
|
*/
|
|
public function edit(string $userId)
|
|
{
|
|
$user = GatewayUser::findOrFail($userId);
|
|
$budgets = Budget::all();
|
|
|
|
return view('gateway-users.edit', compact('user', 'budgets'));
|
|
}
|
|
|
|
/**
|
|
* Update the specified gateway user in storage.
|
|
*/
|
|
public function update(Request $request, string $userId)
|
|
{
|
|
$user = GatewayUser::findOrFail($userId);
|
|
|
|
$validated = $request->validate([
|
|
'alias' => 'nullable|string|max:255',
|
|
'budget_id' => 'nullable|exists:budgets,budget_id',
|
|
'metadata' => 'nullable|array',
|
|
]);
|
|
|
|
$user->update($validated);
|
|
|
|
return redirect()
|
|
->route('gateway-users.show', $user->user_id)
|
|
->with('success', 'Gateway User updated successfully!');
|
|
}
|
|
|
|
/**
|
|
* Remove the specified gateway user from storage.
|
|
*/
|
|
public function destroy(string $userId)
|
|
{
|
|
$user = GatewayUser::findOrFail($userId);
|
|
|
|
// Delete associated API keys and usage logs
|
|
$user->apiKeys()->delete();
|
|
$user->usageLogs()->delete();
|
|
$user->delete();
|
|
|
|
return redirect()
|
|
->route('gateway-users.index')
|
|
->with('success', 'Gateway User deleted successfully!');
|
|
}
|
|
|
|
/**
|
|
* Toggle block status of a gateway user.
|
|
*/
|
|
public function toggleBlock(string $userId)
|
|
{
|
|
$user = GatewayUser::findOrFail($userId);
|
|
$user->blocked = !$user->blocked;
|
|
$user->save();
|
|
|
|
$status = $user->blocked ? 'blocked' : 'unblocked';
|
|
|
|
return redirect()
|
|
->back()
|
|
->with('success', "User has been {$status} successfully!");
|
|
}
|
|
|
|
/**
|
|
* Bulk actions for gateway users.
|
|
*/
|
|
public function bulkAction(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'action' => 'required|in:block,unblock,delete',
|
|
'user_ids' => 'required|array|min:1',
|
|
'user_ids.*' => 'exists:users,user_id',
|
|
]);
|
|
|
|
$count = 0;
|
|
|
|
switch ($validated['action']) {
|
|
case 'block':
|
|
GatewayUser::whereIn('user_id', $validated['user_ids'])
|
|
->update(['blocked' => true]);
|
|
$count = count($validated['user_ids']);
|
|
$message = "{$count} user(s) have been blocked successfully!";
|
|
break;
|
|
|
|
case 'unblock':
|
|
GatewayUser::whereIn('user_id', $validated['user_ids'])
|
|
->update(['blocked' => false]);
|
|
$count = count($validated['user_ids']);
|
|
$message = "{$count} user(s) have been unblocked successfully!";
|
|
break;
|
|
|
|
case 'delete':
|
|
foreach ($validated['user_ids'] as $userId) {
|
|
$user = GatewayUser::find($userId);
|
|
if ($user) {
|
|
$user->apiKeys()->delete();
|
|
$user->usageLogs()->delete();
|
|
$user->delete();
|
|
$count++;
|
|
}
|
|
}
|
|
$message = "{$count} user(s) have been deleted successfully!";
|
|
break;
|
|
}
|
|
|
|
return redirect()
|
|
->route('gateway-users.index')
|
|
->with('success', $message);
|
|
}
|
|
|
|
/**
|
|
* Get user statistics for a given time period.
|
|
*/
|
|
private function getUserStatistics(string $userId, int $days)
|
|
{
|
|
return \App\Models\UsageLog::where('user_id', $userId)
|
|
->where('timestamp', '>=', now()->subDays($days))
|
|
->selectRaw('
|
|
COUNT(*) as total_requests,
|
|
SUM(prompt_tokens) as total_prompt_tokens,
|
|
SUM(completion_tokens) as total_completion_tokens,
|
|
SUM(total_tokens) as total_tokens,
|
|
SUM(cost) as total_cost,
|
|
AVG(total_tokens) as avg_tokens_per_request
|
|
')
|
|
->first();
|
|
}
|
|
}
|