Add traffic limit functionality

- Add traffic_limit field to vpn_clients table (migration 007)
- Add traffic limit management methods in VpnClient class
- Add API endpoints: set-traffic-limit, traffic-limit-status, overlimit
- Add UI for setting limits when creating clients
- Add traffic limit column in clients table with visual indicators
- Add automatic traffic limit check via cron (bin/check_traffic_limits.php)
- Add translations for traffic limits (6 languages)
- Update README with traffic limit documentation
This commit is contained in:
infosave2007
2025-11-08 09:56:25 +03:00
parent 5510e0b7b1
commit b6cf9cbab7
13 changed files with 378 additions and 16 deletions
+113
View File
@@ -396,6 +396,7 @@ Router::post('/servers/{id}/clients/create', function ($params) {
$serverId = (int)$params['id'];
$clientName = trim($_POST['name'] ?? '');
$expiresInDays = !empty($_POST['expires_in_days']) ? (int)$_POST['expires_in_days'] : null;
$trafficLimitGb = !empty($_POST['traffic_limit_gb']) ? (float)$_POST['traffic_limit_gb'] : null;
if (empty($clientName)) {
redirect('/servers/' . $serverId . '?error=Client+name+is+required');
@@ -415,6 +416,14 @@ Router::post('/servers/{id}/clients/create', function ($params) {
}
$clientId = VpnClient::create($serverId, $user['id'], $clientName, $expiresInDays);
// Set traffic limit if specified
if ($trafficLimitGb !== null) {
$client = new VpnClient($clientId);
$limitBytes = (int)($trafficLimitGb * 1073741824); // Convert GB to bytes
$client->setTrafficLimit($limitBytes);
}
redirect('/clients/' . $clientId);
} catch (Exception $e) {
redirect('/servers/' . $serverId . '?error=' . urlencode($e->getMessage()));
@@ -1322,6 +1331,110 @@ Router::get('/api/clients/expiring', function () {
}
});
// Set client traffic limit
Router::post('/api/clients/{id}/set-traffic-limit', function ($params) {
header('Content-Type: application/json');
$user = JWT::requireAuth();
if (!$user) return;
$clientId = (int)$params['id'];
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
// limit_bytes can be null (unlimited) or positive integer
$limitBytes = isset($data['limit_bytes']) ? (int)$data['limit_bytes'] : null;
if ($limitBytes !== null && $limitBytes < 0) {
http_response_code(400);
echo json_encode(['error' => 'limit_bytes must be positive or null for unlimited']);
return;
}
try {
$client = new VpnClient($clientId);
$clientData = $client->getData();
// Check ownership
if ($clientData['user_id'] != $user['id'] && $user['role'] !== 'admin') {
http_response_code(403);
echo json_encode(['error' => 'Forbidden']);
return;
}
$client->setTrafficLimit($limitBytes);
echo json_encode([
'success' => true,
'limit_bytes' => $limitBytes,
'limit_gb' => $limitBytes ? round($limitBytes / 1073741824, 2) : null
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
});
// Check client traffic limit status
Router::get('/api/clients/{id}/traffic-limit-status', function ($params) {
header('Content-Type: application/json');
$user = JWT::requireAuth();
if (!$user) return;
$clientId = (int)$params['id'];
try {
$client = new VpnClient($clientId);
$clientData = $client->getData();
// Check ownership
if ($clientData['user_id'] != $user['id'] && $user['role'] !== 'admin') {
http_response_code(403);
echo json_encode(['error' => 'Forbidden']);
return;
}
$status = $client->getTrafficLimitStatus();
echo json_encode([
'success' => true,
'status' => $status
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
});
// Get clients over traffic limit
Router::get('/api/clients/overlimit', function () {
header('Content-Type: application/json');
$user = JWT::requireAuth();
if (!$user) return;
try {
$clients = VpnClient::getClientsOverLimit();
// Filter by user if not admin
if ($user['role'] !== 'admin') {
$clients = array_filter($clients, function($c) use ($user) {
return $c['user_id'] == $user['id'];
});
}
echo json_encode([
'success' => true,
'clients' => array_values($clients),
'count' => count($clients)
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
});
/**
* SETTINGS ROUTES
*/