diff --git a/backend/auth/otp/providers.php b/backend/auth/otp/providers.php
index 3ede793..f30e7fb 100644
--- a/backend/auth/otp/providers.php
+++ b/backend/auth/otp/providers.php
@@ -52,8 +52,8 @@ function sendKazumiSms(string $receiver, string $otp): bool {
*/
function getNabehBearerToken(): ?string {
global $redis;
-
- // 1. Try to read cached token from Redis (TTL 24 hours)
+
+ // 1. Try fetching from Redis first
if ($redis) {
try {
$cachedToken = $redis->get('nabeh_bearer_token');
@@ -61,16 +61,18 @@ function getNabehBearerToken(): ?string {
return $cachedToken;
}
} catch (Exception $e) {
- error_log("⚠️ [Nabeh Auth Redis] Error reading token: " . $e->getMessage());
+ $msg = "⚠️ [Nabeh Auth Redis] Error reading token: " . $e->getMessage();
+ error_log($msg); echo $msg . "
";
}
}
// 2. Token not cached, authenticate via Nabeh Login API
$email = getenv('NABEH_EMAIL');
$password = getenv('NABEH_PASSWORD');
-
+
if (!$email || !$password) {
- error_log("⚠️ [Nabeh Auth] Missing NABEH_EMAIL or NABEH_PASSWORD environment variables.");
+ $msg = "⚠️ [Nabeh Auth] Missing NABEH_EMAIL or NABEH_PASSWORD environment variables.";
+ error_log($msg); echo $msg . "
";
return null;
}
@@ -87,19 +89,24 @@ function getNabehBearerToken(): ?string {
if ($response) {
$decoded = json_decode($response, true);
$token = $decoded['token'] ?? $decoded['message']['token'] ?? $decoded['jwt'] ?? $decoded['access_token'] ?? null;
-
if ($token) {
- // Cache token in Redis for 24 hours (86400 seconds)
+
+ // 3. Cache token in Redis for 24h
if ($redis) {
try {
$redis->setex('nabeh_bearer_token', 86400, $token);
} catch (Exception $e) {
- error_log("⚠️ [Nabeh Auth Redis Cache Save] Error saving token: " . $e->getMessage());
+ $msg = "⚠️ [Nabeh Auth Redis Cache Save] Error saving token: " . $e->getMessage();
+ error_log($msg); echo $msg . "
";
}
}
return $token;
}
- error_log("❌ [Nabeh Auth] Failed to extract token from login response: " . $response);
+ $msg = "❌ [Nabeh Auth] Failed to extract token from login response: " . $response;
+ error_log($msg); echo $msg . "
";
+ } else {
+ $msg = "❌ [Nabeh Auth] Empty response from login API cURL.";
+ error_log($msg); echo $msg . "
";
}
return null;
}
@@ -115,7 +122,8 @@ function getNabehBearerToken(): ?string {
function sendNabehOtp(string $receiver, string $otp, string $method = 'text'): bool {
$bearerToken = getNabehBearerToken();
if (!$bearerToken) {
- error_log("⚠️ [Nabeh OTP] Failed to obtain dynamic JWT Bearer token.");
+ $msg = "⚠️ [Nabeh OTP] Failed to obtain dynamic JWT Bearer token.";
+ error_log($msg); echo $msg . "
";
return false;
}
@@ -129,9 +137,6 @@ function sendNabehOtp(string $receiver, string $otp, string $method = 'text'): b
} elseif ($method === 'image') {
$type = 'image';
}
- // elseif ($method === 'flash_call') {
- // $type = 'flash_call';
- // }
$apiUrl = 'https://nabeh.intaleqapp.com/api/otp/send';
$payload = [
@@ -150,7 +155,11 @@ function sendNabehOtp(string $receiver, string $otp, string $method = 'text'): b
if ($decoded && ($decoded['success'] ?? false)) {
return true;
}
- error_log("❌ [Nabeh OTP] API returned failure response: " . $response);
+ $msg = "❌ [Nabeh OTP] API returned failure response: " . $response;
+ error_log($msg); echo $msg . "
";
+ } else {
+ $msg = "❌ [Nabeh OTP] Empty response from cURL.";
+ error_log($msg); echo $msg . "
";
}
return false;
}
@@ -217,12 +226,14 @@ function curlCall(string $method, string $url, string $data, array $headers): ?s
curl_close($ch);
if ($error) {
- error_log("⚠️ [OTP cURL] Error calling $url: $error");
+ $msg = "⚠️ [OTP cURL] Error calling $url: $error";
+ error_log($msg); echo $msg . "
";
return null;
}
if ($httpCode !== 200) {
- error_log("⚠️ [OTP cURL] Non-200 HTTP code $httpCode from $url. Response: $response");
+ $msg = "⚠️ [OTP cURL] Non-200 HTTP code $httpCode from $url. Response: $response";
+ error_log($msg); echo $msg . "
";
}
return $response;
diff --git a/backend/auth/otp/request.php b/backend/auth/otp/request.php
index ba442c8..e930ecb 100644
--- a/backend/auth/otp/request.php
+++ b/backend/auth/otp/request.php
@@ -2,6 +2,11 @@
// File: backend/auth/otp/request.php
// Unified OTP request endpoint with geographical routing (Syria, Egypt, Jordan)
+// Enable error reporting for debug
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
require_once __DIR__ . '/../../core/bootstrap.php';
require_once __DIR__ . '/../../functions.php';
require_once __DIR__ . '/providers.php';
diff --git a/backend/schema_primary.sql b/backend/schema_primary.sql
index 7fba399..153c273 100644
--- a/backend/schema_primary.sql
+++ b/backend/schema_primary.sql
@@ -206,7 +206,7 @@ CREATE TABLE `car_locations` (
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
-/*!50003 CREATE*/ /*!50017 DEFINER=`siroUserDB1`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
+/*!50003 CREATE*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END */;;
DELIMITER ;
@@ -223,7 +223,7 @@ DELIMITER ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
-/*!50003 CREATE*/ /*!50017 DEFINER=`siroUserDB1`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
+/*!50003 CREATE*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END IF;
@@ -1144,7 +1144,7 @@ CREATE TABLE `passenger_opening_locations` (
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
-/*!50003 CREATE*/ /*!50017 DEFINER=`siroUserDB1`@`%`*/ /*!50003 TRIGGER `trg_before_insert_passenger_opening_locations` BEFORE INSERT ON `passenger_opening_locations` FOR EACH ROW BEGIN
+/*!50003 CREATE*/ /*!50003 TRIGGER `trg_before_insert_passenger_opening_locations` BEFORE INSERT ON `passenger_opening_locations` FOR EACH ROW BEGIN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END */;;
DELIMITER ;
@@ -1162,7 +1162,7 @@ DELIMITER ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
-/*!50003 CREATE*/ /*!50017 DEFINER=`siroUserDB1`@`%`*/ /*!50003 TRIGGER `trg_before_update_passenger_opening_locations` BEFORE UPDATE ON `passenger_opening_locations` FOR EACH ROW BEGIN
+/*!50003 CREATE*/ /*!50003 TRIGGER `trg_before_update_passenger_opening_locations` BEFORE UPDATE ON `passenger_opening_locations` FOR EACH ROW BEGIN
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END IF;
diff --git a/siro_admin/lib/views/admin/marketing/marketing_page.dart b/siro_admin/lib/views/admin/marketing/marketing_page.dart
index ac9aafd..07abc8e 100644
--- a/siro_admin/lib/views/admin/marketing/marketing_page.dart
+++ b/siro_admin/lib/views/admin/marketing/marketing_page.dart
@@ -438,8 +438,6 @@ class MarketingPage extends StatelessWidget {
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -571,6 +569,13 @@ class MarketingPage extends StatelessWidget {
return const Center(child: CircularProgressIndicator(color: _accent));
}
+ return ListView.builder(
+ padding: const EdgeInsets.all(16),
+ itemCount: c.campaignsLog.length,
+ itemBuilder: (context, index) {
+ final log = c.campaignsLog[index];
+ final channel = log['channel']?.toString().toUpperCase() ?? 'SMS';
+
Color channelColor = _info;
if (channel == 'SMS') channelColor = _success;
if (channel == 'WHATSAPP') channelColor = const Color(0xFF25D366);
@@ -602,19 +607,19 @@ class MarketingPage extends StatelessWidget {
),
),
Text(
- log['created_at'] ?? "",
+ log['created_at']?.toString() ?? "",
style: const TextStyle(color: _textSecondary, fontSize: 11),
),
],
),
const SizedBox(height: 12),
Text(
- log['campaign_name'] ?? "حملة استعادة تلقائية",
+ log['campaign_name']?.toString() ?? "حملة استعادة تلقائية",
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: _textPrimary),
),
const SizedBox(height: 8),
Text(
- log['message_body'] ?? "",
+ log['message_body']?.toString() ?? "",
style: const TextStyle(fontSize: 12, color: _textSecondary, height: 1.4),
),
const SizedBox(height: 12),
diff --git a/siro_rider/ios/Podfile.lock b/siro_rider/ios/Podfile.lock
index 396abac..8fcd937 100644
--- a/siro_rider/ios/Podfile.lock
+++ b/siro_rider/ios/Podfile.lock
@@ -80,16 +80,6 @@ PODS:
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
- - GoogleMLKit/BarcodeScanning (7.0.0):
- - GoogleMLKit/MLKitCore
- - MLKitBarcodeScanning (~> 6.0.0)
- - GoogleMLKit/MLKitCore (7.0.0):
- - MLKitCommon (~> 12.0.0)
- - GoogleToolboxForMac/Defines (4.2.1)
- - GoogleToolboxForMac/Logger (4.2.1):
- - GoogleToolboxForMac/Defines (= 4.2.1)
- - "GoogleToolboxForMac/NSData+zlib (4.2.1)":
- - GoogleToolboxForMac/Defines (= 4.2.1)
- GoogleUtilities/AppDelegateSwizzler (8.1.1):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
@@ -138,26 +128,6 @@ PODS:
- maplibre_gl (0.25.0):
- Flutter
- MapLibre (= 6.19.1)
- - MLImage (1.0.0-beta6)
- - MLKitBarcodeScanning (6.0.0):
- - MLKitCommon (~> 12.0)
- - MLKitVision (~> 8.0)
- - MLKitCommon (12.0.0):
- - GoogleDataTransport (~> 10.0)
- - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- - GoogleUtilities/Logger (~> 8.0)
- - GoogleUtilities/UserDefaults (~> 8.0)
- - GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- - MLKitVision (8.0.0):
- - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- - GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- - MLImage (= 1.0.0-beta6)
- - MLKitCommon (~> 12.0)
- - mobile_scanner (6.0.2):
- - Flutter
- - GoogleMLKit/BarcodeScanning (~> 7.0.0)
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0)
@@ -221,7 +191,6 @@ DEPENDENCIES:
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- location (from `.symlinks/plugins/location/ios`)
- maplibre_gl (from `.symlinks/plugins/maplibre_gl/ios`)
- - mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`)
@@ -248,16 +217,10 @@ SPEC REPOS:
- FirebaseInstallations
- FirebaseMessaging
- GoogleDataTransport
- - GoogleMLKit
- - GoogleToolboxForMac
- GoogleUtilities
- GTMSessionFetcher
- IOSSecuritySuite
- MapLibre
- - MLImage
- - MLKitBarcodeScanning
- - MLKitCommon
- - MLKitVision
- nanopb
- PromisesObjC
- RecaptchaInterop
@@ -311,8 +274,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/location/ios"
maplibre_gl:
:path: ".symlinks/plugins/maplibre_gl/ios"
- mobile_scanner:
- :path: ".symlinks/plugins/mobile_scanner/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
permission_handler_apple:
@@ -366,8 +327,6 @@ SPEC CHECKSUMS:
flutter_webrtc: ec91d94b484ad49cf191ef93413f64a40ffd3b4c
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
- GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
- GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
GoogleUtilities: 4f2618a4a1e762a1ee134a1e2323bba9843e06da
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
image_cropper: 64567491beea6cd1bc4b11948e2babb590de5826
@@ -380,11 +339,6 @@ SPEC CHECKSUMS:
location: 155caecf9da4f280ab5fe4a55f94ceccfab838f8
MapLibre: 7f24faba45439f80ccb0f83393c29fa32cb81952
maplibre_gl: a2114567cbd1065866614fbd34dfb75ab782aaa2
- MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
- MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
- MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
- MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
- mobile_scanner: af8f71879eaba2bbcb4d86c6a462c3c0e7f23036
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
permission_handler_apple: 92d754bbaa7361d436db2d6c3c1c2a0fdcec462e