import 'package:get/get.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; /// Oldal-/funkció-szintű jogosultságok kezelése — PROJEKTENKÉNT. /// /// A jogosultságokat a Supabase `app_permissions` tábla tárolja /// (user_id + area + project_id), ahol a project_id NULL értéke /// GLOBÁLIS jogot jelent (minden projektre érvényes — pl. admin). /// A tényleges védelmet a Supabase-oldali RLS adja /// (`has_permission(area, project_id)`), ez a service csak a UI-t /// vezérli (menüpont elrejtése, üzenet). class PermissionService extends GetxService { static PermissionService get to => Get.find(); static const areaContacts = 'contacts'; static const areaAdmin = 'admin'; SupabaseClient get _client => Supabase.instance.client; /// projectId → engedélyezett területek. A `null` kulcs a GLOBÁLIS /// (minden projektre érvényes) jogokat tárolja. final _areasByProject = >{}.obs; final isLoaded = false.obs; /// [projectId] nélkül CSAK a globális jogokat nézi — projekt-specifikus /// ellenőrzéshez mindig add meg az aktív projektet. bool can(String area, {String? projectId}) { if (_areasByProject[null]?.contains(area) ?? false) return true; if (projectId != null) { return _areasByProject[projectId]?.contains(area) ?? false; } return false; } bool canContacts({String? projectId}) => can(areaContacts, projectId: projectId); /// Az admin jogot szándékosan globálisnak tartjuk — ha ezt is /// projektenként szeretnéd, ugyanígy paraméterezhető. bool get canAdmin => can(areaAdmin); @override void onInit() { super.onInit(); reload(); _client.auth.onAuthStateChange.listen((_) => reload()); } Future reload() async { final user = _client.auth.currentUser; if (user == null) { _areasByProject.clear(); isLoaded.value = true; return; } try { final rows = await _client .from('terepi_seged_app_permissions') .select('area, project_id') .eq('user_id', user.id); final map = >{}; for (final r in rows) { final pid = r['project_id'] as String?; map.putIfAbsent(pid, () => {}).add(r['area'] as String); } _areasByProject ..clear() ..addAll(map); } catch (_) { _areasByProject.clear(); } finally { _areasByProject.refresh(); isLoaded.value = true; } } }