import 'package:flutter/material.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; /// Utility class to fix the users policy class FixUsersPolicyUtil { /// Fix the users policy to prevent infinite recursion static Future fixUsersPolicy(BuildContext context) async { try { // Show loading dialog showDialog( context: context, barrierDismissible: false, builder: (context) => const AlertDialog( content: Column( mainAxisSize: MainAxisSize.min, children: [ CircularProgressIndicator(), SizedBox(height: 16), Text('Memperbaiki kebijakan tabel users...'), ], ), ), ); final client = Supabase.instance.client; // Ensure execute_sql function exists await _ensureExecuteSqlExists(client); // Step 1: Drop the problematic policy await client.rpc( 'execute_sql', params: { 'sql_statement': 'DROP POLICY IF EXISTS users_policy ON auth.users;', }, ); print('Dropped problematic policy'); // Step 2: Ensure user_roles table exists try { await client.rpc( 'execute_sql', params: { 'sql_statement': ''' CREATE TABLE IF NOT EXISTS public.user_roles ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE, role text NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); ''', }, ); print('Ensured user_roles table exists'); } catch (e) { print('Error creating user_roles table: $e'); } // Step 3: Create a new policy without recursion await client.rpc( 'execute_sql', params: { 'sql_statement': ''' CREATE POLICY users_policy ON auth.users FOR SELECT USING ( auth.uid() = id OR EXISTS ( SELECT 1 FROM public.user_roles WHERE user_id = auth.uid() AND role = 'admin' ) ); ''', }, ); print('Created new policy'); // Step 4: Ensure current user is admin final userId = client.auth.currentUser?.id; if (userId != null) { try { await client.rpc( 'execute_sql', params: { 'sql_statement': ''' INSERT INTO public.user_roles (user_id, role) VALUES ('$userId', 'admin') ON CONFLICT (user_id, role) DO NOTHING; ''', }, ); print('Ensured current user is admin'); } catch (e) { // Try without constraint if the first attempt fails try { await client.rpc( 'execute_sql', params: { 'sql_statement': ''' INSERT INTO public.user_roles (user_id, role) SELECT '$userId', 'admin' WHERE NOT EXISTS ( SELECT 1 FROM public.user_roles WHERE user_id = '$userId' AND role = 'admin' ); ''', }, ); print('Ensured current user is admin (alternative method)'); } catch (innerE) { print('Error ensuring admin status: $innerE'); } } } // Step 5: Grant necessary permissions await client.rpc( 'execute_sql', params: { 'sql_statement': 'GRANT SELECT ON auth.users TO authenticated; GRANT SELECT ON auth.users TO anon;', }, ); print('Granted permissions'); // Close the dialog Navigator.pop(context); // Show success message ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Kebijakan tabel users berhasil diperbaiki'), backgroundColor: Colors.green, ), ); } catch (e) { print('Error fixing users policy: $e'); // Close the dialog if it's open Navigator.pop(context); // Show error message ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Gagal memperbaiki kebijakan tabel users: ${e.toString()}', ), backgroundColor: Colors.red, ), ); } } /// Ensure the execute_sql function exists static Future _ensureExecuteSqlExists(SupabaseClient client) async { try { // Try to call the function to see if it exists await client.rpc('execute_sql', params: {'sql_statement': 'SELECT 1;'}); print('execute_sql function exists'); } catch (e) { print('execute_sql function may not exist, trying to create it: $e'); // Function doesn't exist, create it using raw SQL query try { // Try to access a table to check connection await client.from('_temp_execute_sql_check').select(); } catch (e) { print('Error checking database connection: $e'); // Try a different approach try { // Try to access profiles table which should exist final response = await client.from('profiles').select().limit(1); print('Database connection works: ${response.length} profiles found'); } catch (e) { print('Could not connect to database: $e'); } } } } }