marco.pms.mobileapp/lib/helpers/services/permission_service.dart
2025-12-06 17:34:01 +05:30

120 lines
4.2 KiB
Dart

import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:on_field_work/model/user_permission.dart';
import 'package:on_field_work/model/employees/employee_info.dart';
import 'package:on_field_work/model/projects_model.dart';
import 'package:on_field_work/helpers/services/storage/local_storage.dart';
import 'package:on_field_work/helpers/services/auth_service.dart';
import 'package:on_field_work/helpers/services/api_endpoints.dart';
import 'package:on_field_work/helpers/utils/encryption_helper.dart';
class PermissionService {
static final Map<String, Map<String, dynamic>> _userDataCache = {};
static const String _baseUrl = ApiEndpoints.baseUrl;
static Future<Map<String, dynamic>> fetchAllUserData(
String token, {
bool hasRetried = false,
}) async {
logSafe("Fetching user data...");
final cached = _userDataCache[token];
if (cached != null) {
logSafe("User data cache hit.");
return cached;
}
final uri = Uri.parse("$_baseUrl/user/profile");
final headers = {'Authorization': 'Bearer $token'};
try {
final response = await http.get(uri, headers: headers);
final statusCode = response.statusCode;
if (response.body.isEmpty || response.body.trim().isEmpty) {
logSafe("❌ Empty user data response — auto logout");
await _handleUnauthorized();
throw Exception("Empty user data response");
}
final decrypted = decryptResponse(response.body);
if (decrypted == null) {
logSafe("❌ Failed to decrypt user data — auto logout", level: LogLevel.error);
await _handleUnauthorized();
throw Exception("Decryption failed for user data");
}
final data = decrypted is Map ? decrypted['data'] ?? decrypted : null;
if (data == null || data is! Map<String, dynamic>) {
logSafe("❌ Decrypted user data is invalid — auto logout", level: LogLevel.error);
await _handleUnauthorized();
throw Exception("Invalid decrypted user data");
}
if (statusCode == 200) {
final result = {
'permissions': _parsePermissions(data['featurePermissions']),
'employeeInfo': _parseEmployeeInfo(data['employeeInfo']),
'projects': _parseProjectsInfo(data['projects']),
};
_userDataCache[token] = result;
logSafe("User data fetched and decrypted successfully.");
return result;
}
if (statusCode == 401 && !hasRetried) {
logSafe("Unauthorized. Attempting token refresh...", level: LogLevel.warning);
final refreshed = await AuthService.refreshToken();
if (refreshed) {
final newToken = await LocalStorage.getJwtToken();
if (newToken != null && newToken.isNotEmpty) {
return fetchAllUserData(newToken, hasRetried: true);
}
}
await _handleUnauthorized();
logSafe("Token refresh failed. Redirecting to login.", level: LogLevel.warning);
throw Exception('Unauthorized. Token refresh failed.');
}
final errorMsg = data['message'] ?? 'Unknown error';
logSafe("Failed to fetch user data: $errorMsg", level: LogLevel.warning);
throw Exception('Failed to fetch user data: $errorMsg');
} catch (e, stacktrace) {
logSafe("Exception while fetching user data", level: LogLevel.error, error: e, stackTrace: stacktrace);
rethrow;
}
}
static Future<void> _handleUnauthorized() async {
logSafe("Clearing tokens and redirecting to login due to unauthorized access.", level: LogLevel.warning);
await LocalStorage.removeToken('jwt_token');
await LocalStorage.removeToken('refresh_token');
await LocalStorage.setLoggedInUser(false);
Get.offAllNamed('/auth/login-option');
}
static List<UserPermission> _parsePermissions(List<dynamic>? permissions) {
logSafe("Parsing user permissions...");
if (permissions == null) return [];
return permissions.map((perm) => UserPermission.fromJson({'id': perm})).toList();
}
static EmployeeInfo _parseEmployeeInfo(Map<String, dynamic>? data) {
logSafe("Parsing employee info...");
if (data == null) throw Exception("Employee data missing");
return EmployeeInfo.fromJson(data);
}
static List<ProjectInfo> _parseProjectsInfo(List<dynamic>? projects) {
logSafe("Parsing projects info...");
if (projects == null) return [];
return projects.map((proj) => ProjectInfo.fromJson(proj)).toList();
}
}