- Introduced a new `logSafe` function for consistent logging with sensitivity handling. - Replaced direct logger calls with `logSafe` in `api_service.dart`, `app_initializer.dart`, `auth_service.dart`, `permission_service.dart`, and `my_image_compressor.dart`. - Enhanced error handling and logging in various service methods to capture exceptions and provide more context. - Updated image compression logging to include quality and size metrics. - Improved app initialization logging to capture success and error states. - Ensured sensitive information is not logged directly.
105 lines
3.8 KiB
Dart
105 lines
3.8 KiB
Dart
import 'dart:convert';
|
|
import 'package:get/get.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import 'package:marco/helpers/services/app_logger.dart';
|
|
import 'package:marco/model/user_permission.dart';
|
|
import 'package:marco/model/employee_info.dart';
|
|
import 'package:marco/model/projects_model.dart';
|
|
import 'package:marco/helpers/services/storage/local_storage.dart';
|
|
import 'package:marco/helpers/services/auth_service.dart';
|
|
import 'package:marco/helpers/services/api_endpoints.dart';
|
|
|
|
class PermissionService {
|
|
static final Map<String, Map<String, dynamic>> _userDataCache = {};
|
|
static const String _baseUrl = ApiEndpoints.baseUrl;
|
|
|
|
/// Fetches all user-related data (permissions, employee info, projects)
|
|
static Future<Map<String, dynamic>> fetchAllUserData(
|
|
String token, {
|
|
bool hasRetried = false,
|
|
}) async {
|
|
logSafe("Fetching user data...", sensitive: true);
|
|
|
|
if (_userDataCache.containsKey(token)) {
|
|
logSafe("User data cache hit.", sensitive: true);
|
|
return _userDataCache[token]!;
|
|
}
|
|
|
|
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 (statusCode == 200) {
|
|
logSafe("User data fetched successfully.");
|
|
final data = json.decode(response.body)['data'];
|
|
|
|
final result = {
|
|
'permissions': _parsePermissions(data['featurePermissions']),
|
|
'employeeInfo': _parseEmployeeInfo(data['employeeInfo']),
|
|
'projects': _parseProjectsInfo(data['projects']),
|
|
};
|
|
|
|
_userDataCache[token] = result;
|
|
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 error = json.decode(response.body)['message'] ?? 'Unknown error';
|
|
logSafe("Failed to fetch user data: $error", level: LogLevel.warning);
|
|
throw Exception('Failed to fetch user data: $error');
|
|
} catch (e, stacktrace) {
|
|
logSafe("Exception while fetching user data", level: LogLevel.error, error: e, stackTrace: stacktrace);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
/// Clears auth data and redirects to login
|
|
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');
|
|
}
|
|
|
|
/// Converts raw permission data into list of `UserPermission`
|
|
static List<UserPermission> _parsePermissions(List<dynamic> permissions) {
|
|
logSafe("Parsing user permissions...");
|
|
return permissions
|
|
.map((id) => UserPermission.fromJson({'id': id}))
|
|
.toList();
|
|
}
|
|
|
|
/// Converts raw employee JSON into `EmployeeInfo`
|
|
static EmployeeInfo _parseEmployeeInfo(Map<String, dynamic> data) {
|
|
logSafe("Parsing employee info...");
|
|
return EmployeeInfo.fromJson(data);
|
|
}
|
|
|
|
/// Converts raw projects JSON into list of `ProjectInfo`
|
|
static List<ProjectInfo> _parseProjectsInfo(List<dynamic> projects) {
|
|
logSafe("Parsing projects info...");
|
|
return projects.map((proj) => ProjectInfo.fromJson(proj)).toList();
|
|
}
|
|
}
|