feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ. الخريطة: backend · payment_server · loction_server · ride_server · passenger_server · docker · dashboard · stress_test → الجذر siro_rider → apps/rider siro_driver → apps/driver siro_admin → dashboards/admin siro_service → dashboards/service android_bot → apps/android_bot socialBot → apps/socialBot نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب) لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً: كل ما يلي يصير فرقاً مقروءاً مقابل المصدر. لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز، سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh (ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و dashboards/transit-web). ⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة: 1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر): كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner. 2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist) يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً. 3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع → يجب ضمّ الحزم داخله أسوة بـ apps/rider. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9909d9b4c1
commit
4d8414c96b
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$driver_id = filterRequest("driver_id");
|
||||
$points = filterRequest("points"); // Reward points amount
|
||||
$challenge_id = filterRequest("challenge_id");
|
||||
|
||||
if (!$driver_id || !$points || !$challenge_id) {
|
||||
jsonError("Missing required parameters");
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$con->beginTransaction();
|
||||
|
||||
// 1. Get Country and Currency to determine Cash Multiplier
|
||||
$stmtKazan = $con->prepare("SELECT country, currency FROM kazan LIMIT 1");
|
||||
$stmtKazan->execute();
|
||||
$kazanData = $stmtKazan->fetch(PDO::FETCH_ASSOC);
|
||||
$country = $kazanData['country'] ?? 'Syria';
|
||||
$currency = $kazanData['currency'] ?? 'SYP';
|
||||
|
||||
switch ($currency) {
|
||||
case 'SYP':
|
||||
$rate = 100.0; // 1 point = 100 SYP (e.g. 50 points = 5,000 SYP)
|
||||
break;
|
||||
case 'EGP':
|
||||
$rate = 1.0; // 1 point = 1 EGP (e.g. 50 points = 50 EGP)
|
||||
break;
|
||||
case 'JOD':
|
||||
default:
|
||||
$rate = 0.05; // 1 point = 0.05 JOD (e.g. 50 points = 2.5 JOD)
|
||||
break;
|
||||
}
|
||||
|
||||
$cashAmount = $points * $rate;
|
||||
|
||||
// 2. S2S Wallet credit to Payment Server
|
||||
$walletServer = "https://walletintaleq.intaleq.xyz";
|
||||
if (strtolower($country) == 'jordan') {
|
||||
$walletServer = getenv('WALLET_SERVER_JORDAN') ?: "https://walletintaleq.intaleq.xyz";
|
||||
} elseif (strtolower($country) == 'egypt') {
|
||||
$walletServer = getenv('WALLET_SERVER_EGYPT') ?: "https://walletintaleq.intaleq.xyz";
|
||||
} else {
|
||||
$walletServer = getenv('WALLET_SERVER_SYRIA') ?: "https://walletintaleq.intaleq.xyz";
|
||||
}
|
||||
|
||||
$paymentID = "CHL_" . time();
|
||||
$walletUrl = "$walletServer/v2/main/ride/driverWallet/add_s2s_reward.php";
|
||||
|
||||
$payload = [
|
||||
"driverID" => $driver_id,
|
||||
"paymentID" => $paymentID,
|
||||
"amount" => $cashAmount,
|
||||
"paymentMethod" => $challenge_id,
|
||||
"points" => $points
|
||||
];
|
||||
|
||||
$ch = curl_init($walletUrl);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => http_build_query($payload),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
'X-S2S-Api-Key: ' . getenv('S2S_SHARED_KEY')
|
||||
]
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlErr = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$s2sSuccess = false;
|
||||
$s2sMessage = "";
|
||||
if (!$curlErr && $httpCode === 200) {
|
||||
$resDecoded = json_decode($response, true);
|
||||
if ($resDecoded && isset($resDecoded['status'])) {
|
||||
if ($resDecoded['status'] === 'success') {
|
||||
$s2sSuccess = true;
|
||||
} else {
|
||||
$s2sMessage = $resDecoded['message'] ?? "Unknown S2S failure";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$s2sSuccess) {
|
||||
$errMsg = $s2sMessage ?: ($curlErr ?: "HTTP $httpCode - Response: $response");
|
||||
throw new Exception($errMsg);
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
jsonSuccess("Reward claimed successfully as " . $cashAmount . " " . $currency);
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($con->inTransaction()) {
|
||||
$con->rollBack();
|
||||
}
|
||||
error_log("claimChallengeReward Error: " . $e->getMessage());
|
||||
jsonError("An internal error occurred. Please try again later.");
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$driver_id = filterRequest("driver_id");
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
COALESCE(ROUND(AVG(behavior_score), 1), 100) as avg_score,
|
||||
COALESCE(SUM(hard_brakes), 0) as total_hard_brakes,
|
||||
COALESCE(MAX(max_speed), 0) as max_speed
|
||||
FROM `driver_behavior`
|
||||
WHERE driver_id = :driver_id
|
||||
AND created_at >= DATE(NOW()) - INTERVAL 30 DAY
|
||||
";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($row && $row['max_speed'] !== null) {
|
||||
jsonSuccess([$row]);
|
||||
} else {
|
||||
jsonSuccess([[
|
||||
"avg_score" => 100,
|
||||
"total_hard_brakes" => 0,
|
||||
"max_speed" => 0
|
||||
]]);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$driver_id = filterRequest("driver_id");
|
||||
|
||||
if (!$driver_id) {
|
||||
jsonError("Missing driver_id");
|
||||
}
|
||||
|
||||
try {
|
||||
global $redis;
|
||||
$redisKey = "gamification_dashboard:{$driver_id}";
|
||||
|
||||
// 1. Try to read from Redis first
|
||||
if (isset($redis)) {
|
||||
try {
|
||||
$cached = $redis->get($redisKey);
|
||||
if ($cached) {
|
||||
$data = json_decode($cached, true);
|
||||
if ($data) {
|
||||
jsonSuccess($data);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis read error in getGamificationDashboard: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to Database & External API
|
||||
// Get Country and Currency Info from Environment Variables (to avoid querying kazan table)
|
||||
$country = getenv('APP_COUNTRY') ?: getenv('COUNTRY') ?: "Jordan";
|
||||
$currency = getenv('APP_CURRENCY') ?: getenv('CURRENCY') ?: "JOD";
|
||||
$kazan = ["country" => $country, "currency" => $currency];
|
||||
|
||||
// 2. Get Total Completed Trips
|
||||
$stmtTrips = $con->prepare("SELECT COUNT(*) as count FROM `ride` WHERE driver_id = :driver_id AND status = 'Finished'");
|
||||
$stmtTrips->execute([':driver_id' => $driver_id]);
|
||||
$totalTrips = (int)($stmtTrips->fetchColumn() ?: 0);
|
||||
|
||||
// 3. Get Average Rating
|
||||
$stmtRate = $con->prepare("SELECT COALESCE(ROUND(AVG(rating), 2), 5.0) as rating FROM ratingDriver WHERE driver_id = :driver_id");
|
||||
$stmtRate->execute([':driver_id' => $driver_id]);
|
||||
$avgRating = (float)($stmtRate->fetchColumn() ?: 5.0);
|
||||
|
||||
// 4. Get Referral Counts (Installed/Verified)
|
||||
$stmtDInv = $con->prepare("SELECT COUNT(*) FROM invites WHERE driverId = :driver_id AND isInstall = 1");
|
||||
$stmtDInv->execute([':driver_id' => $driver_id]);
|
||||
$driverInvites = (int)($stmtDInv->fetchColumn() ?: 0);
|
||||
|
||||
$stmtPInv = $con->prepare("SELECT COUNT(*) FROM invitesToPassengers WHERE driverId = :driver_id AND isInstall = 1");
|
||||
$stmtPInv->execute([':driver_id' => $driver_id]);
|
||||
$passengerInvites = (int)($stmtPInv->fetchColumn() ?: 0);
|
||||
|
||||
$totalReferrals = $driverInvites + $passengerInvites;
|
||||
|
||||
// 5. Get Driver Behavior (Last 30 Days)
|
||||
$stmtBehavior = $con->prepare("
|
||||
SELECT
|
||||
COALESCE(ROUND(AVG(behavior_score), 1), 100) as avg_score,
|
||||
COALESCE(SUM(hard_brakes), 0) as total_hard_brakes,
|
||||
COALESCE(MAX(max_speed), 0) as max_speed
|
||||
FROM `driver_behavior`
|
||||
WHERE driver_id = :driver_id
|
||||
AND created_at >= DATE(NOW()) - INTERVAL 30 DAY
|
||||
");
|
||||
$stmtBehavior->execute([':driver_id' => $driver_id]);
|
||||
$behavior = $stmtBehavior->fetch(PDO::FETCH_ASSOC) ?: ["avg_score" => 100.0, "total_hard_brakes" => 0, "max_speed" => 0.0];
|
||||
|
||||
// 6. Get Today's Completed Trips & Earnings (Local Ride Database)
|
||||
$stmtTodayTrips = $con->prepare("SELECT COUNT(*) FROM `ride` WHERE driver_id = :driver_id AND status = 'Finished' AND DATE(created_at) = CURDATE()");
|
||||
$stmtTodayTrips->execute([':driver_id' => $driver_id]);
|
||||
$todayTrips = (int)($stmtTodayTrips->fetchColumn() ?: 0);
|
||||
|
||||
$stmtTodayEarnings = $con->prepare("SELECT COALESCE(SUM(price_for_driver), 0) FROM `ride` WHERE driver_id = :driver_id AND status = 'Finished' AND DATE(created_at) = CURDATE()");
|
||||
$stmtTodayEarnings->execute([':driver_id' => $driver_id]);
|
||||
$todayEarnings = (float)($stmtTodayEarnings->fetchColumn() ?: 0.0);
|
||||
|
||||
// 7. Get Claimed Challenge Points from Payment Server via S2S
|
||||
$walletServer = "https://walletintaleq.intaleq.xyz";
|
||||
if (strtolower($kazan["country"]) == 'jordan') {
|
||||
$walletServer = getenv('WALLET_SERVER_JORDAN') ?: "https://walletintaleq.intaleq.xyz";
|
||||
} elseif (strtolower($kazan["country"]) == 'egypt') {
|
||||
$walletServer = getenv('WALLET_SERVER_EGYPT') ?: "https://walletintaleq.intaleq.xyz";
|
||||
} else {
|
||||
$walletServer = getenv('WALLET_SERVER_SYRIA') ?: "https://walletintaleq.intaleq.xyz";
|
||||
}
|
||||
|
||||
$walletUrl = "$walletServer/v2/main/ride/driverWallet/get_s2s_wallet_dashboard.php";
|
||||
|
||||
$ch = curl_init($walletUrl);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => http_build_query(["driverID" => $driver_id]),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
'X-S2S-Api-Key: ' . getenv('S2S_SHARED_KEY')
|
||||
]
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlErr = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$challengePoints = 0;
|
||||
if (!$curlErr && $httpCode === 200) {
|
||||
$resDecoded = json_decode($response, true);
|
||||
if ($resDecoded && isset($resDecoded['status']) && $resDecoded['status'] === 'success') {
|
||||
$challengePoints = (int)($resDecoded['message']['challengePoints'] ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Calculate Normalized Points
|
||||
$normalizedPoints = ($totalTrips * 10) + ($totalReferrals * 100) + ((int)$behavior['avg_score'] * 2) + $challengePoints;
|
||||
|
||||
// 9. Fetch Available Challenges
|
||||
$stmtCh = $con->prepare("SELECT * FROM gamification_challenges WHERE is_active = 1 AND country = :country ORDER BY target_count ASC");
|
||||
$stmtCh->execute([':country' => $kazan['country']]);
|
||||
$challengesRaw = $stmtCh->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$challenges = [];
|
||||
$tier = 'Bronze'; // Placeholder logic
|
||||
foreach ($challengesRaw as $chRaw) {
|
||||
$isCompleted = false;
|
||||
$isClaimed = false;
|
||||
|
||||
$challenges[] = [
|
||||
'id' => (int)$chRaw['id'],
|
||||
'title' => $chRaw['title'],
|
||||
'description' => $chRaw['description'],
|
||||
'type' => $chRaw['challenge_type'],
|
||||
'target' => (int)$chRaw['target_count'],
|
||||
'reward_amount' => (float)$chRaw['reward_amount'],
|
||||
'reward_type' => $chRaw['reward_type'],
|
||||
'is_completed' => $isCompleted,
|
||||
'is_claimed' => $isClaimed
|
||||
];
|
||||
}
|
||||
|
||||
$responseData = [
|
||||
"country" => $kazan["country"],
|
||||
"currency" => $kazan["currency"],
|
||||
"totalTrips" => $totalTrips,
|
||||
"averageRating" => $avgRating,
|
||||
"totalReferrals" => $totalReferrals,
|
||||
"driverInvites" => $driverInvites,
|
||||
"passengerInvites" => $passengerInvites,
|
||||
"behaviorScore" => (float)$behavior["avg_score"],
|
||||
"hardBrakes" => (int)$behavior["total_hard_brakes"],
|
||||
"maxSpeed" => (float)$behavior["max_speed"],
|
||||
"todayTrips" => $todayTrips,
|
||||
"todayEarnings" => $todayEarnings,
|
||||
"totalPoints" => $normalizedPoints,
|
||||
"tier" => $tier,
|
||||
"challenges" => $challenges
|
||||
];
|
||||
|
||||
// 10. Save the compiled data into Redis
|
||||
if (isset($redis)) {
|
||||
try {
|
||||
$redis->setex($redisKey, 900, json_encode($responseData));
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis write error in getGamificationDashboard: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
jsonSuccess($responseData);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("getGamificationDashboard Error: " . $e->getMessage());
|
||||
jsonError("An internal error occurred. Please try again later.");
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$type = isset($_POST['type']) ? filterRequest("type") : 'trips';
|
||||
|
||||
try {
|
||||
global $redis;
|
||||
$redisKey = "gamification_leaderboard:{$type}";
|
||||
|
||||
// 1. Try to read from Redis first
|
||||
if (isset($redis)) {
|
||||
try {
|
||||
$cached = $redis->get($redisKey);
|
||||
if ($cached) {
|
||||
$data = json_decode($cached, true);
|
||||
if ($data !== null) {
|
||||
jsonSuccess($data);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis read error in getLeaderboard: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to Database
|
||||
if ($type === 'earnings') {
|
||||
$sql = "
|
||||
SELECT
|
||||
d.id as driver_id,
|
||||
COALESCE(d.name, d.nameArabic, d.firstName, 'Driver') as name,
|
||||
d.personal_photo as photoUrl,
|
||||
COALESCE(SUM(r.price_for_driver), 0) as value
|
||||
FROM `driver` d
|
||||
JOIN `ride` r ON d.id = r.driver_id
|
||||
WHERE r.status = 'Finished'
|
||||
AND r.created_at >= DATE(NOW() - INTERVAL WEEKDAY(NOW()) DAY)
|
||||
GROUP BY d.id
|
||||
ORDER BY value DESC
|
||||
LIMIT 10
|
||||
";
|
||||
} else {
|
||||
// Default to trips
|
||||
$sql = "
|
||||
SELECT
|
||||
d.id as driver_id,
|
||||
COALESCE(d.name, d.nameArabic, d.firstName, 'Driver') as name,
|
||||
d.personal_photo as photoUrl,
|
||||
COUNT(r.id) as value
|
||||
FROM `driver` d
|
||||
JOIN `ride` r ON d.id = r.driver_id
|
||||
WHERE r.status = 'Finished'
|
||||
AND r.created_at >= DATE(NOW() - INTERVAL WEEKDAY(NOW()) DAY)
|
||||
GROUP BY d.id
|
||||
ORDER BY value DESC
|
||||
LIMIT 10
|
||||
";
|
||||
}
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute();
|
||||
} catch (PDOException $e) {
|
||||
error_log("getLeaderboard Error: " . $e->getMessage());
|
||||
jsonError("Database error occurred");
|
||||
}
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Add Rank manually to support older MySQL versions
|
||||
$rank = 1;
|
||||
foreach ($rows as &$row) {
|
||||
$row['rank'] = $rank++;
|
||||
}
|
||||
|
||||
$responseData = $rows;
|
||||
} else {
|
||||
$responseData = [];
|
||||
}
|
||||
|
||||
// 3. Save the DB result into Redis for future reads
|
||||
if (isset($redis)) {
|
||||
try {
|
||||
// Cache leaderboard for 1 hour (3600 seconds)
|
||||
$redis->setex($redisKey, 3600, json_encode($responseData));
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis write error in getLeaderboard: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
jsonSuccess($responseData);
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$driver_id = filterRequest("driver_id");
|
||||
|
||||
// Driver invites count
|
||||
$sqlDriver = "SELECT COUNT(*) as total FROM invites WHERE driverId = :driver_id AND isInstall = 1";
|
||||
$stmtD = $con->prepare($sqlDriver);
|
||||
$stmtD->bindParam(':driver_id', $driver_id, PDO::PARAM_INT);
|
||||
$stmtD->execute();
|
||||
$driverCount = $stmtD->fetchColumn();
|
||||
|
||||
// Passenger invites count
|
||||
$sqlPass = "SELECT COUNT(*) as total FROM invitesToPassengers WHERE driverId = :driver_id AND isInstall = 1";
|
||||
$stmtP = $con->prepare($sqlPass);
|
||||
$stmtP->bindParam(':driver_id', $driver_id, PDO::PARAM_INT);
|
||||
$stmtP->execute();
|
||||
$passengerCount = $stmtP->fetchColumn();
|
||||
|
||||
// Rewards calculation (100 pts per driver, 50 pts per passenger)
|
||||
$totalRewards = ($driverCount * 100) + ($passengerCount * 50);
|
||||
|
||||
jsonSuccess([
|
||||
[
|
||||
"driverInvites" => (int)$driverCount,
|
||||
"passengerInvites" => (int)$passengerCount,
|
||||
"totalRewards" => $totalRewards
|
||||
]
|
||||
]);
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$driver_id = filterRequest("driver_id");
|
||||
|
||||
try {
|
||||
$sql = "
|
||||
SELECT
|
||||
DATE(r.created_at) as day,
|
||||
COUNT(r.id) as trips,
|
||||
COALESCE(SUM(r.price_for_driver), 0) as earnings,
|
||||
COALESCE(SUM(TIMESTAMPDIFF(MINUTE, r.time, r.endtime))/60, 0) as hours
|
||||
FROM `ride` r
|
||||
WHERE r.driver_id = :driver_id
|
||||
AND r.status = 'Finished'
|
||||
AND r.created_at >= DATE(NOW()) - INTERVAL 6 DAY
|
||||
GROUP BY DATE(r.created_at)
|
||||
ORDER BY DATE(r.created_at) ASC
|
||||
";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
jsonSuccess($rows);
|
||||
} else {
|
||||
jsonSuccess([]);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Return empty but log error
|
||||
error_log("getWeeklyAggregate Error: " . $e->getMessage());
|
||||
jsonError("Database error occurred");
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$driver_id = filterRequest("driver_id");
|
||||
if (empty($driver_id)) {
|
||||
jsonError("Missing driver_id");
|
||||
exit;
|
||||
}
|
||||
|
||||
global $redis;
|
||||
$redisKey = "driver_streak:{$driver_id}";
|
||||
|
||||
// 1. Try to read from Redis first (Cache-Aside pattern)
|
||||
if (isset($redis)) {
|
||||
try {
|
||||
$cached = $redis->get($redisKey);
|
||||
if ($cached) {
|
||||
$data = json_decode($cached, true);
|
||||
if ($data) {
|
||||
// Return immediately if found in cache!
|
||||
jsonSuccess($data);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis read error in get_streak: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to Database if not found in Redis
|
||||
$stmt = $con->prepare("SELECT current_streak, zero_commission_until FROM driver_streaks WHERE driver_id = ?");
|
||||
$stmt->execute([$driver_id]);
|
||||
$streak = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($streak) {
|
||||
$now = new DateTime();
|
||||
$until = new DateTime($streak['zero_commission_until']);
|
||||
|
||||
$isActive = false;
|
||||
if ($streak['zero_commission_until'] !== '2000-01-01 00:00:00' && $now < $until) {
|
||||
$isActive = true;
|
||||
}
|
||||
|
||||
$responseData = [
|
||||
'streak_count' => intval($streak['current_streak']),
|
||||
'is_zero_commission_active' => $isActive,
|
||||
'zero_commission_until' => $streak['zero_commission_until']
|
||||
];
|
||||
} else {
|
||||
// Default if no record yet
|
||||
$responseData = [
|
||||
'streak_count' => 0,
|
||||
'is_zero_commission_active' => false,
|
||||
'zero_commission_until' => '2000-01-01 00:00:00'
|
||||
];
|
||||
}
|
||||
|
||||
// 3. Save the DB result into Redis for future reads
|
||||
if (isset($redis)) {
|
||||
try {
|
||||
// Cache it for 2 hours (7200 seconds)
|
||||
$redis->setex($redisKey, 7200, json_encode($responseData));
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis write error in get_streak: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
jsonSuccess($responseData);
|
||||
?>
|
||||
Reference in New Issue
Block a user