Update: 2026-06-25 18:39:01
This commit is contained in:
@@ -32,6 +32,7 @@ $fingerprint = filterRequest("fingerprint") ?: '';
|
|||||||
$gender = filterRequest("gender") ?? 'Male';
|
$gender = filterRequest("gender") ?? 'Male';
|
||||||
$birthdate = filterRequest("birthdate") ?? date('Y-m-d');
|
$birthdate = filterRequest("birthdate") ?? date('Y-m-d');
|
||||||
$site = filterRequest("site") ?? 'main';
|
$site = filterRequest("site") ?? 'main';
|
||||||
|
$country = filterRequest("country") ?? 'Jordan';
|
||||||
|
|
||||||
if (empty($name) || empty($password) || empty($role)) {
|
if (empty($name) || empty($password) || empty($role)) {
|
||||||
jsonError("Missing required fields (name, password, role).");
|
jsonError("Missing required fields (name, password, role).");
|
||||||
@@ -70,8 +71,8 @@ try {
|
|||||||
} else {
|
} else {
|
||||||
// الإضافة لجدول المستخدمين (خدمة العملاء)
|
// الإضافة لجدول المستخدمين (خدمة العملاء)
|
||||||
// أضفنا site و last_name (كقيمة افتراضية فارغة إذا لم تتوفر)
|
// أضفنا site و last_name (كقيمة افتراضية فارغة إذا لم تتوفر)
|
||||||
$sql = "INSERT INTO users (id, fingerprint, fingerprint_hash, phone, email, gender, password, birthdate, user_type, first_name, last_name, site, created_at)
|
$sql = "INSERT INTO users (id, fingerprint, fingerprint_hash, phone, email, gender, password, birthdate, user_type, first_name, last_name, site, country, created_at)
|
||||||
VALUES (:id, :fp, :fp_hash, :phone, :email, :gender, :pass, :bdate, 'service', :fname, :lname, :site, NOW())";
|
VALUES (:id, :fp, :fp_hash, :phone, :email, :gender, :pass, :bdate, 'service', :fname, :lname, :site, :country, NOW())";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
':id' => $uniqueId,
|
':id' => $uniqueId,
|
||||||
@@ -84,7 +85,8 @@ try {
|
|||||||
':bdate' => $birthdate,
|
':bdate' => $birthdate,
|
||||||
':fname' => $encName,
|
':fname' => $encName,
|
||||||
':lname' => '', // last_name is empty for now
|
':lname' => '', // last_name is empty for now
|
||||||
':site' => $site
|
':site' => $site,
|
||||||
|
':country' => $country
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
63
backend/Admin/Staff/add_super_admin.php
Normal file
63
backend/Admin/Staff/add_super_admin.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Admin/Staff/add_super_admin.php
|
||||||
|
* إضافة مشرف عام (Super Admin) — استخدام لمرة واحدة
|
||||||
|
*/
|
||||||
|
require_once __DIR__ . '/../../core/bootstrap.php';
|
||||||
|
|
||||||
|
// $adminKey = filterRequest('admin_key') ?? '';
|
||||||
|
// $expected = getenv('MIGRATION_ADMIN_KEY');
|
||||||
|
// if (empty($adminKey) || empty($expected) || !hash_equals($expected, $adminKey)) {
|
||||||
|
// http_response_code(403);
|
||||||
|
// exit(json_encode(['error' => 'Access denied. Admin key required.']));
|
||||||
|
// }
|
||||||
|
|
||||||
|
$con = Database::get('main');
|
||||||
|
|
||||||
|
$name = filterRequest('name') ?: 'Super Admin';
|
||||||
|
$email = filterRequest('email') ?: '';
|
||||||
|
$phone = filterRequest('phone') ?: '';
|
||||||
|
$fingerprint = filterRequest('fingerprint') ?: '';
|
||||||
|
$password = filterRequest('password') ?: bin2hex(random_bytes(8));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hashedPass = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
$encName = $encryptionHelper->encryptData($name);
|
||||||
|
$encPhone = $phone ? $encryptionHelper->encryptData($phone) : '';
|
||||||
|
$encEmail = $email ? $encryptionHelper->encryptData($email) : '';
|
||||||
|
$encFp = $fingerprint ? $encryptionHelper->encryptData($fingerprint) : '';
|
||||||
|
$fpHash = $fingerprint ? hash('sha256', $fingerprint) : '';
|
||||||
|
$uniqueId = bin2hex(random_bytes(16));
|
||||||
|
|
||||||
|
$check = $con->prepare("SELECT id FROM adminUser WHERE role = 'super_admin' LIMIT 1");
|
||||||
|
$check->execute();
|
||||||
|
if ($check->fetch()) {
|
||||||
|
echo "<h2>⚠️ Super Admin already exists.</h2>";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "INSERT INTO adminUser (id, fingerprint, fingerprint_hash, name, phone, email, password, role, created_at)
|
||||||
|
VALUES (:id, :fp, :fp_hash, :name, :phone, :email, :pass, 'super_admin', NOW())";
|
||||||
|
$stmt = $con->prepare($sql);
|
||||||
|
$stmt->execute([
|
||||||
|
':id' => $uniqueId,
|
||||||
|
':fp' => $encFp,
|
||||||
|
':fp_hash' => $fpHash,
|
||||||
|
':name' => $encName,
|
||||||
|
':phone' => $encPhone,
|
||||||
|
':email' => $encEmail,
|
||||||
|
':pass' => $hashedPass,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
echo "<h2>✅ Super Admin created successfully!</h2>";
|
||||||
|
echo "<p><b>ID:</b> $uniqueId</p>";
|
||||||
|
echo "<p><b>Name:</b> $name</p>";
|
||||||
|
echo "<p><b>Password:</b> $password</p>";
|
||||||
|
echo "<p style='color:red;'><b>⚠️ Save this password. Delete this file after use.</b></p>";
|
||||||
|
} else {
|
||||||
|
echo "<h2>❌ Failed to create Super Admin.</h2>";
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "<h2>❌ Error: " . htmlspecialchars($e->getMessage()) . "</h2>";
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ $driverId = filterRequest("driverId");
|
|||||||
|
|
||||||
$sql = "SELECT d.*, cr.*
|
$sql = "SELECT d.*, cr.*
|
||||||
FROM `driver` d
|
FROM `driver` d
|
||||||
JOIN `CarRegistration` cr ON cr.driverID = d.id
|
LEFT JOIN `CarRegistration` cr ON cr.driverID = d.id
|
||||||
WHERE d.id = :driverId ";
|
WHERE d.id = :driverId ";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ $sql = "SELECT
|
|||||||
notesForDriverService.note
|
notesForDriverService.note
|
||||||
FROM
|
FROM
|
||||||
phone_verification
|
phone_verification
|
||||||
INNER JOIN -- نستخدم INNER JOIN لضمان جلب من لديهم ملاحظات فقط
|
INNER JOIN
|
||||||
`notesForDriverService`
|
`notesForDriverService`
|
||||||
ON
|
ON
|
||||||
`notesForDriverService`.`phone` = `phone_verification`.`phone_number`
|
`notesForDriverService`.`phone` = `phone_verification`.`phone_number`
|
||||||
WHERE
|
WHERE
|
||||||
`notesForDriverService`.`note` != 'delete'
|
`notesForDriverService`.`note` != 'delete'
|
||||||
ORDER BY
|
ORDER BY
|
||||||
`phone_verification`.`created_at` DESC -- الترتيب حسب تاريخ التحقق لأنه العمود الموجود
|
`phone_verification`.`created_at` DESC
|
||||||
LIMIT 400;
|
LIMIT 400;
|
||||||
";
|
";
|
||||||
|
|
||||||
@@ -24,7 +24,6 @@ $stmt->execute();
|
|||||||
if ($stmt->rowCount() > 0) {
|
if ($stmt->rowCount() > 0) {
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// فك تشفير أرقام الهواتف فقط للإخراج
|
|
||||||
foreach ($rows as &$row) {
|
foreach ($rows as &$row) {
|
||||||
if (!empty($row['phone'])) {
|
if (!empty($row['phone'])) {
|
||||||
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
|
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
|
||||||
@@ -42,4 +41,3 @@ if ($stmt->rowCount() > 0) {
|
|||||||
} else {
|
} else {
|
||||||
jsonError("No Phone verified yet found");
|
jsonError("No Phone verified yet found");
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
@@ -105,10 +105,6 @@ try {
|
|||||||
$expires_in = $ttl;
|
$expires_in = $ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// توليد مفتاح HMAC فريد للمستخدم (للتوافق مع CRUD الجديد)
|
|
||||||
$hmacKey = hash_hmac('sha256', (string)$user['id'], getenv('SECRET_KEY_HMAC'));
|
|
||||||
|
|
||||||
// ✅ FIX H-05: لا نعيد مفتاح HMAC أبداً (يُحسب على العميل بنفس المعادلة)
|
|
||||||
printSuccess([
|
printSuccess([
|
||||||
"message" => "Login successful",
|
"message" => "Login successful",
|
||||||
"data" => $user,
|
"data" => $user,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class StaffController extends GetxController {
|
|||||||
|
|
||||||
String selectedGender = 'Male';
|
String selectedGender = 'Male';
|
||||||
String selectedRole = 'service'; // 'admin' or 'service'
|
String selectedRole = 'service'; // 'admin' or 'service'
|
||||||
|
String selectedCountry = 'Jordan';
|
||||||
|
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ class StaffController extends GetxController {
|
|||||||
"birthdate": birthdateController.text.trim(),
|
"birthdate": birthdateController.text.trim(),
|
||||||
"fingerprint": fingerprint,
|
"fingerprint": fingerprint,
|
||||||
"site": "main", // القيمة الافتراضية للفرع
|
"site": "main", // القيمة الافتراضية للفرع
|
||||||
|
"country": selectedCountry,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,14 @@ class AddStaffPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildDropdown(
|
||||||
|
label: "البلد",
|
||||||
|
value: controller.selectedCountry,
|
||||||
|
items: const ['Jordan', 'Syria', 'Egypt'],
|
||||||
|
onChanged: (val) => controller.selectedCountry = val!,
|
||||||
|
fillColor: inputColor,
|
||||||
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
GetBuilder<StaffController>(
|
GetBuilder<StaffController>(
|
||||||
builder: (controller) => SizedBox(
|
builder: (controller) => SizedBox(
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ PODS:
|
|||||||
- nanopb/encode (= 3.30910.0)
|
- nanopb/encode (= 3.30910.0)
|
||||||
- nanopb/decode (3.30910.0)
|
- nanopb/decode (3.30910.0)
|
||||||
- nanopb/encode (3.30910.0)
|
- nanopb/encode (3.30910.0)
|
||||||
|
- package_info_plus (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@@ -127,6 +129,7 @@ DEPENDENCIES:
|
|||||||
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
- local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`)
|
- local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`)
|
||||||
|
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||||
@@ -167,6 +170,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
local_auth_darwin:
|
local_auth_darwin:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin
|
||||||
|
package_info_plus:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
@@ -191,11 +196,12 @@ SPEC CHECKSUMS:
|
|||||||
FirebaseSessions: b9a92c1c51bbb81e78fc3142cda6d925d700f8e7
|
FirebaseSessions: b9a92c1c51bbb81e78fc3142cda6d925d700f8e7
|
||||||
flutter_image_compress_macos: e68daf54bb4bf2144c580fd4d151c949cbf492f0
|
flutter_image_compress_macos: e68daf54bb4bf2144c580fd4d151c949cbf492f0
|
||||||
flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54
|
flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54
|
||||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
|
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
|
||||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||||
|
package_info_plus: 122abb51244f66eead59ce7c9c200d6b53111779
|
||||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ class LoginController extends GetxController {
|
|||||||
await storage.write(key: 'password', value: pass);
|
await storage.write(key: 'password', value: pass);
|
||||||
await box.write(BoxName.employeename, userData['first_name']);
|
await box.write(BoxName.employeename, userData['first_name']);
|
||||||
await box.write(BoxName.password, pass);
|
await box.write(BoxName.password, pass);
|
||||||
|
if (userData['country'] != null) {
|
||||||
|
await box.write(BoxName.countryCode, userData['country']);
|
||||||
|
}
|
||||||
|
|
||||||
Get.offAll(() => Main());
|
Get.offAll(() => Main());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -144,7 +144,8 @@ class DriversCantRegister extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
// Edit button → go to registration form
|
// Edit button → go to review page (only if driverId exists)
|
||||||
|
if (driver['driverId'] != null)
|
||||||
buildActionButton(
|
buildActionButton(
|
||||||
icon: CupertinoIcons
|
icon: CupertinoIcons
|
||||||
.pencil_ellipsis_rectangle,
|
.pencil_ellipsis_rectangle,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ReviewDriverController extends GetxController {
|
|||||||
'profile_picture': Icons.person,
|
'profile_picture': Icons.person,
|
||||||
};
|
};
|
||||||
|
|
||||||
String get country => box.read('countryCode')?.toString() ?? 'Syria';
|
String get country => box.read('countryCode')?.toString() ?? 'Jordan';
|
||||||
|
|
||||||
static const Map<String, List<List<dynamic>>> fieldConfig = {
|
static const Map<String, List<List<dynamic>>> fieldConfig = {
|
||||||
'id_front': [
|
'id_front': [
|
||||||
|
|||||||
Reference in New Issue
Block a user