Update Saqel Platform: 2026-09-08 17:51:07
This commit is contained in:
@@ -6,6 +6,9 @@ import '../utils/app_logger.dart';
|
|||||||
|
|
||||||
/// Enterprise Storage Service with Device-Bound Payload Obfuscation & Secure KeyStore/Keychain
|
/// Enterprise Storage Service with Device-Bound Payload Obfuscation & Secure KeyStore/Keychain
|
||||||
class StorageService {
|
class StorageService {
|
||||||
|
// Keeps a newly issued session available during this app run if the macOS
|
||||||
|
// debug runner has no Keychain entitlement. Production still uses Keychain.
|
||||||
|
static final Map<String, String> _volatileStore = <String, String>{};
|
||||||
final FlutterSecureStorage _secureStorage;
|
final FlutterSecureStorage _secureStorage;
|
||||||
|
|
||||||
StorageService({FlutterSecureStorage? secureStorage})
|
StorageService({FlutterSecureStorage? secureStorage})
|
||||||
@@ -26,6 +29,7 @@ class StorageService {
|
|||||||
static const String _keyDeviceId = 'saqel_device_id';
|
static const String _keyDeviceId = 'saqel_device_id';
|
||||||
|
|
||||||
Future<void> _writeSafe(String key, String value) async {
|
Future<void> _writeSafe(String key, String value) async {
|
||||||
|
_volatileStore[key] = value;
|
||||||
try {
|
try {
|
||||||
await _secureStorage.write(key: key, value: value);
|
await _secureStorage.write(key: key, value: value);
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
@@ -38,10 +42,11 @@ class StorageService {
|
|||||||
final val = await _secureStorage.read(key: key);
|
final val = await _secureStorage.read(key: key);
|
||||||
if (val != null && val.isNotEmpty) return val;
|
if (val != null && val.isNotEmpty) return val;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
return null;
|
return _volatileStore[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _deleteSafe(String key) async {
|
Future<void> _deleteSafe(String key) async {
|
||||||
|
_volatileStore.remove(key);
|
||||||
try {
|
try {
|
||||||
await _secureStorage.delete(key: key);
|
await _secureStorage.delete(key: key);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class AuthRepository {
|
|||||||
required String identityToken,
|
required String identityToken,
|
||||||
required String fullName,
|
required String fullName,
|
||||||
required String nationalId,
|
required String nationalId,
|
||||||
String gradeLevel = 'tawjihi_2008',
|
String gradeLevel = 'grade_10',
|
||||||
String stream = 'scientific',
|
String stream = 'scientific',
|
||||||
}) async {
|
}) async {
|
||||||
final res = await _api.post(
|
final res = await _api.post(
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
required String identityToken,
|
required String identityToken,
|
||||||
required String fullName,
|
required String fullName,
|
||||||
required String nationalId,
|
required String nationalId,
|
||||||
String gradeLevel = 'tawjihi_2008',
|
String gradeLevel = 'grade_10',
|
||||||
String stream = 'scientific',
|
String stream = 'scientific',
|
||||||
}) async {
|
}) async {
|
||||||
AppLogger.log('Setting up profile for $fullName ($nationalId)...', tag: 'AUTH_CUBIT');
|
AppLogger.log('Setting up profile for $fullName ($nationalId)...', tag: 'AUTH_CUBIT');
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
final TextEditingController _fullNameController = TextEditingController();
|
final TextEditingController _fullNameController = TextEditingController();
|
||||||
|
|
||||||
String _selectedRole = 'student';
|
String _selectedRole = 'student';
|
||||||
final String _selectedGrade = 'tawjihi_2008';
|
String _selectedGrade = 'grade_10';
|
||||||
String _selectedStream = 'scientific';
|
String _selectedStream = 'scientific';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -440,7 +440,30 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 18),
|
const SizedBox(height: 18),
|
||||||
|
|
||||||
// Stream Selector (العلمي / الأدبي)
|
Text(
|
||||||
|
'الصف الدراسي',
|
||||||
|
style: AppTypography.titleMedium.copyWith(color: AppColors.textSecondaryDark, fontSize: 13),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
('grade_10', 'الصف العاشر'),
|
||||||
|
('grade_11', 'الأول ثانوي'),
|
||||||
|
('grade_12', 'الثاني ثانوي'),
|
||||||
|
].map((grade) => ChoiceChip(
|
||||||
|
label: Text(grade.$2),
|
||||||
|
selected: _selectedGrade == grade.$1,
|
||||||
|
onSelected: isLoading ? null : (_) => setState(() {
|
||||||
|
_selectedGrade = grade.$1;
|
||||||
|
if (_selectedGrade == 'grade_10') _selectedStream = 'general';
|
||||||
|
}),
|
||||||
|
)).toList(),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 18),
|
||||||
|
|
||||||
|
// Stream Selector (only secondary grades have a stream)
|
||||||
|
if (_selectedGrade != 'grade_10') ...[
|
||||||
Text(
|
Text(
|
||||||
'الفرع الأكاديمي',
|
'الفرع الأكاديمي',
|
||||||
style: AppTypography.titleMedium.copyWith(color: AppColors.textSecondaryDark, fontSize: 13),
|
style: AppTypography.titleMedium.copyWith(color: AppColors.textSecondaryDark, fontSize: 13),
|
||||||
@@ -501,6 +524,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
LuxuryButton(
|
LuxuryButton(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import '../utils/app_logger.dart';
|
|||||||
|
|
||||||
/// Ultra-Resilient Storage Service for Teacher Studio
|
/// Ultra-Resilient Storage Service for Teacher Studio
|
||||||
class StorageService {
|
class StorageService {
|
||||||
|
static final Map<String, String> _volatileStore = <String, String>{};
|
||||||
final FlutterSecureStorage _secureStorage;
|
final FlutterSecureStorage _secureStorage;
|
||||||
|
|
||||||
StorageService({FlutterSecureStorage? secureStorage})
|
StorageService({FlutterSecureStorage? secureStorage})
|
||||||
@@ -21,6 +22,7 @@ class StorageService {
|
|||||||
static const String _keyUser = 'saqel_teacher_user_data';
|
static const String _keyUser = 'saqel_teacher_user_data';
|
||||||
|
|
||||||
Future<void> _writeSafe(String key, String value) async {
|
Future<void> _writeSafe(String key, String value) async {
|
||||||
|
_volatileStore[key] = value;
|
||||||
try {
|
try {
|
||||||
await _secureStorage.write(key: key, value: value);
|
await _secureStorage.write(key: key, value: value);
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
@@ -34,13 +36,15 @@ class StorageService {
|
|||||||
if (val != null && val.isNotEmpty) return val;
|
if (val != null && val.isNotEmpty) return val;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
return null;
|
return _volatileStore[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveToken(String token) async => await _writeSafe(_keyToken, token);
|
Future<void> saveToken(String token) async => await _writeSafe(_keyToken, token);
|
||||||
Future<String?> getToken() async => await _readSafe(_keyToken);
|
Future<String?> getToken() async => await _readSafe(_keyToken);
|
||||||
|
|
||||||
Future<void> clearSession() async {
|
Future<void> clearSession() async {
|
||||||
|
_volatileStore.remove(_keyToken);
|
||||||
|
_volatileStore.remove(_keyUser);
|
||||||
try {
|
try {
|
||||||
await _secureStorage.delete(key: _keyToken);
|
await _secureStorage.delete(key: _keyToken);
|
||||||
await _secureStorage.delete(key: _keyUser);
|
await _secureStorage.delete(key: _keyUser);
|
||||||
|
|||||||
@@ -184,20 +184,20 @@ class TeacherProfileModel {
|
|||||||
grades = [profile['grades_taught'].toString()];
|
grades = [profile['grades_taught'].toString()];
|
||||||
}
|
}
|
||||||
if (grades.isEmpty) {
|
if (grades.isEmpty) {
|
||||||
grades = ['الصف العاشر الأساسي', 'الأول ثانوي العلمي'];
|
grades = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return TeacherProfileModel(
|
return TeacherProfileModel(
|
||||||
id: user['id'] is int ? user['id'] : 1,
|
id: user['id'] is int ? user['id'] : 1,
|
||||||
uuid: user['uuid']?.toString() ?? '',
|
uuid: user['uuid']?.toString() ?? '',
|
||||||
name: user['full_name']?.toString() ?? 'الأستاذ المعتمد',
|
name: user['full_name']?.toString() ?? 'حساب معلم غير مكتمل',
|
||||||
specialization: profile['specialization']?.toString() ?? 'الفيزياء',
|
specialization: profile['specialization']?.toString() ?? 'بانتظار استكمال التخصص',
|
||||||
schoolName: profile['school_name']?.toString() ?? 'مدرسة الملك عبد الله الثاني للتميز',
|
schoolName: profile['school_name']?.toString() ?? '',
|
||||||
gradesTaught: grades,
|
gradesTaught: grades,
|
||||||
bio: profile['bio']?.toString() ?? 'معلم معتمد في منصة صَقِل',
|
bio: profile['bio']?.toString() ?? '',
|
||||||
rating: 4.9,
|
rating: 0,
|
||||||
studentsCount: 42,
|
studentsCount: 0,
|
||||||
lessonsCount: 28,
|
lessonsCount: 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class TeacherRepository {
|
|||||||
'phone_number': phoneNumber,
|
'phone_number': phoneNumber,
|
||||||
'role': 'teacher',
|
'role': 'teacher',
|
||||||
}),
|
}),
|
||||||
).timeout(const Duration(seconds: 6));
|
).timeout(const Duration(seconds: 30));
|
||||||
|
|
||||||
return json.decode(response.body);
|
return json.decode(response.body);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -78,7 +78,7 @@ class TeacherRepository {
|
|||||||
if (fullName != null) 'full_name': fullName,
|
if (fullName != null) 'full_name': fullName,
|
||||||
'device_fingerprint': 'saqel_teacher_flutter',
|
'device_fingerprint': 'saqel_teacher_flutter',
|
||||||
}),
|
}),
|
||||||
).timeout(const Duration(seconds: 6));
|
).timeout(const Duration(seconds: 30));
|
||||||
|
|
||||||
final decoded = json.decode(response.body);
|
final decoded = json.decode(response.body);
|
||||||
if (decoded['status'] == 'success' && decoded['data']?['token'] != null) {
|
if (decoded['status'] == 'success' && decoded['data']?['token'] != null) {
|
||||||
|
|||||||
@@ -86,14 +86,14 @@ class TeacherAuthCubit extends Cubit<TeacherAuthState> {
|
|||||||
try {
|
try {
|
||||||
final res = await repository.verifyOtp(phoneNumber, otp, fullName: fullName);
|
final res = await repository.verifyOtp(phoneNumber, otp, fullName: fullName);
|
||||||
if (res['status'] == 'success') {
|
if (res['status'] == 'success') {
|
||||||
if (specialization != null || schoolName != null || gradesTaught != null) {
|
if ((fullName ?? '').trim().isNotEmpty && (specialization ?? '').trim().isNotEmpty && (schoolName ?? '').trim().isNotEmpty && (gradesTaught?.isNotEmpty ?? false)) {
|
||||||
try {
|
try {
|
||||||
await repository.setupProfile(
|
await repository.setupProfile(
|
||||||
fullName: fullName ?? 'المعلم المعتمد',
|
fullName: fullName!.trim(),
|
||||||
specialization: specialization ?? 'الفيزياء والعلوم التطبيقية',
|
specialization: specialization!.trim(),
|
||||||
schoolName: schoolName ?? 'مدرسة الملك عبد الله الثاني للتميز',
|
schoolName: schoolName!.trim(),
|
||||||
gradesTaught: gradesTaught ?? ['الصف العاشر الأساسي'],
|
gradesTaught: gradesTaught!,
|
||||||
bio: 'معلم معتمد في منصة صقل للتعليم التفاعلي',
|
bio: '',
|
||||||
);
|
);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ class TeacherAuthScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||||
final TextEditingController _phoneController = TextEditingController(text: '0798583052');
|
final TextEditingController _phoneController = TextEditingController();
|
||||||
final TextEditingController _otpController = TextEditingController();
|
final TextEditingController _otpController = TextEditingController();
|
||||||
final TextEditingController _fullNameController = TextEditingController(text: 'المهندس حمزة الغويريين');
|
final TextEditingController _fullNameController = TextEditingController();
|
||||||
final TextEditingController _schoolController = TextEditingController(text: 'مدرسة الملك عبد الله الثاني للتميز');
|
final TextEditingController _schoolController = TextEditingController();
|
||||||
|
|
||||||
String _selectedSubject = 'الفيزياء والعلوم التطبيقية';
|
String? _selectedSubject;
|
||||||
final List<String> _availableSubjects = [
|
final List<String> _availableSubjects = [
|
||||||
'الفيزياء والعلوم التطبيقية',
|
'الفيزياء والعلوم التطبيقية',
|
||||||
'الرياضيات العلمي',
|
'الرياضيات العلمي',
|
||||||
@@ -39,10 +39,7 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
|||||||
'اللغة العربية ومشترك التوجيهي',
|
'اللغة العربية ومشترك التوجيهي',
|
||||||
];
|
];
|
||||||
|
|
||||||
final Set<String> _selectedGrades = {
|
final Set<String> _selectedGrades = {};
|
||||||
'الصف العاشر الأساسي',
|
|
||||||
'الأول ثانوي العلمي',
|
|
||||||
};
|
|
||||||
|
|
||||||
final List<String> _allGrades = [
|
final List<String> _allGrades = [
|
||||||
'الصف التاسع الأساسي',
|
'الصف التاسع الأساسي',
|
||||||
@@ -79,6 +76,10 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
|||||||
SaqelToast.showError(context, 'يرجى إدخال رمز التحقق المكون من 6 أرقام');
|
SaqelToast.showError(context, 'يرجى إدخال رمز التحقق المكون من 6 أرقام');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (_fullNameController.text.trim().isEmpty || _selectedSubject == null || _schoolController.text.trim().isEmpty || _selectedGrades.isEmpty) {
|
||||||
|
SaqelToast.showError(context, 'أكمل الاسم والمادة والمدرسة وصفًا واحدًا على الأقل قبل التحقق');
|
||||||
|
return;
|
||||||
|
}
|
||||||
context.read<TeacherAuthCubit>().verifyOtp(
|
context.read<TeacherAuthCubit>().verifyOtp(
|
||||||
phone,
|
phone,
|
||||||
otp,
|
otp,
|
||||||
|
|||||||
@@ -211,13 +211,13 @@ class _TeacherMainShellState extends State<TeacherMainShell> {
|
|||||||
builder: (context, authState) {
|
builder: (context, authState) {
|
||||||
TeacherProfileModel profile = widget.initialProfile ??
|
TeacherProfileModel profile = widget.initialProfile ??
|
||||||
const TeacherProfileModel(
|
const TeacherProfileModel(
|
||||||
id: 1,
|
id: 0,
|
||||||
uuid: 'tch-01',
|
uuid: '',
|
||||||
name: 'المهندس حمزة الغويريين',
|
name: 'حساب معلم غير مكتمل',
|
||||||
specialization: 'الفيزياء والعلوم التطبيقية',
|
specialization: 'بانتظار استكمال الملف',
|
||||||
schoolName: 'مدرسة الملك عبد الله الثاني للتميز',
|
schoolName: '',
|
||||||
gradesTaught: ['الصف العاشر الأساسي', 'الأول ثانوي العلمي'],
|
gradesTaught: [],
|
||||||
bio: 'معلم معتمد في منصة صَقِل',
|
bio: '',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (authState is TeacherAuthenticated) {
|
if (authState is TeacherAuthenticated) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- device_info_plus (0.0.1):
|
- device_info_plus (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- file_picker (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- flutter_secure_storage_macos (6.1.3):
|
- flutter_secure_storage_macos (6.1.3):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
@@ -10,6 +12,7 @@ PODS:
|
|||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||||
|
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
|
||||||
- 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`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
@@ -17,6 +20,8 @@ DEPENDENCIES:
|
|||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
device_info_plus:
|
device_info_plus:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
|
||||||
|
file_picker:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
|
||||||
flutter_secure_storage_macos:
|
flutter_secure_storage_macos:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
|
||||||
FlutterMacOS:
|
FlutterMacOS:
|
||||||
@@ -26,6 +31,7 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041
|
device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041
|
||||||
|
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
||||||
flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54
|
flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54
|
||||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
|
|||||||
@@ -571,6 +571,7 @@ class AuthController
|
|||||||
|
|
||||||
$identityId = (int)(is_array($decoded) ? ($decoded['identity_id'] ?? 0) : ($decoded->identity_id ?? 0));
|
$identityId = (int)(is_array($decoded) ? ($decoded['identity_id'] ?? 0) : ($decoded->identity_id ?? 0));
|
||||||
$phone = is_array($decoded) ? ($decoded['phone'] ?? '') : ($decoded->phone ?? '');
|
$phone = is_array($decoded) ? ($decoded['phone'] ?? '') : ($decoded->phone ?? '');
|
||||||
|
$deviceFingerprint = trim((string)$request->getHeader('x-device-fingerprint', '')) ?: 'browser_default';
|
||||||
|
|
||||||
// Check if student exists with this National ID
|
// Check if student exists with this National ID
|
||||||
$nationalIdHash = Security::blindIndex($nationalId);
|
$nationalIdHash = Security::blindIndex($nationalId);
|
||||||
@@ -591,7 +592,7 @@ class AuthController
|
|||||||
(int)$student['id'],
|
(int)$student['id'],
|
||||||
$student['uuid'],
|
$student['uuid'],
|
||||||
'student',
|
'student',
|
||||||
'browser_default',
|
$deviceFingerprint,
|
||||||
$phone,
|
$phone,
|
||||||
$student['full_name'],
|
$student['full_name'],
|
||||||
$response,
|
$response,
|
||||||
@@ -661,6 +662,10 @@ class AuthController
|
|||||||
$gradeLevel = trim((string)($body['grade_level'] ?? 'grade_10'));
|
$gradeLevel = trim((string)($body['grade_level'] ?? 'grade_10'));
|
||||||
$stream = trim((string)($body['stream'] ?? 'scientific'));
|
$stream = trim((string)($body['stream'] ?? 'scientific'));
|
||||||
$nationalId = trim((string)($body['national_id'] ?? ''));
|
$nationalId = trim((string)($body['national_id'] ?? ''));
|
||||||
|
$deviceFingerprint = trim((string)($request->getHeader('x-device-fingerprint', '')));
|
||||||
|
if ($deviceFingerprint === '') {
|
||||||
|
$deviceFingerprint = 'browser_default';
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($fullName) || empty($nationalId)) {
|
if (empty($fullName) || empty($nationalId)) {
|
||||||
$response->status(400)->json(['status' => 'error', 'message' => 'الاسم الكامل والرقم الوطني مطلوبان']);
|
$response->status(400)->json(['status' => 'error', 'message' => 'الاسم الكامل والرقم الوطني مطلوبان']);
|
||||||
@@ -701,7 +706,7 @@ class AuthController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->generateSessionAndRespond(
|
$this->generateSessionAndRespond(
|
||||||
$sId, $sUuid, 'student', 'browser_default', $phone, $fullName, $response, 'تم استكمال التسجيل بنجاح',
|
$sId, $sUuid, 'student', $deviceFingerprint, $phone, $fullName, $response, 'تم استكمال التسجيل بنجاح',
|
||||||
$identityId,
|
$identityId,
|
||||||
(int)(is_array($decoded) ? ($decoded['token_version'] ?? 1) : ($decoded->token_version ?? 1)),
|
(int)(is_array($decoded) ? ($decoded['token_version'] ?? 1) : ($decoded->token_version ?? 1)),
|
||||||
null,
|
null,
|
||||||
|
|||||||
Reference in New Issue
Block a user