Compare commits

..

2 Commits

Author SHA1 Message Date
gpt-engineer-app[bot]
bcbb8019bd Implement RPC function for user emails 2025-10-30 18:03:17 +00:00
gpt-engineer-app[bot]
3318fdaa3f Fix: Make test user creation idempotent 2025-10-30 17:53:52 +00:00
4 changed files with 84 additions and 16 deletions

View File

@@ -19,6 +19,7 @@ interface UserProfile {
id: string; id: string;
user_id: string; user_id: string;
username: string; username: string;
email?: string;
display_name?: string; display_name?: string;
avatar_url?: string; avatar_url?: string;
banned: boolean; banned: boolean;
@@ -49,17 +50,15 @@ export function ProfileManager() {
try { try {
setLoading(true); setLoading(true);
// Fetch profiles with user roles // Fetch profiles with emails using secure RPC function
const { data: profilesData, error: profilesError } = await supabase const { data: profilesData, error: profilesError } = await supabase
.from('profiles') .rpc('get_users_with_emails');
.select('*')
.order('created_at', { ascending: false });
if (profilesError) throw profilesError; if (profilesError) throw profilesError;
// Fetch roles for each user // Fetch roles for each user
const profilesWithRoles = await Promise.all( const profilesWithRoles = await Promise.all(
profilesData.map(async (profile) => { (profilesData || []).map(async (profile) => {
const { data: rolesData } = await supabase const { data: rolesData } = await supabase
.from('user_roles') .from('user_roles')
.select('role') .select('role')
@@ -453,7 +452,7 @@ export function ProfileManager() {
targetUser={{ targetUser={{
userId: deletionTarget.user_id, userId: deletionTarget.user_id,
username: deletionTarget.username, username: deletionTarget.username,
email: '', // Email not available in profile data email: deletionTarget.email || 'Email not found',
displayName: deletionTarget.display_name || undefined, displayName: deletionTarget.display_name || undefined,
roles: deletionTarget.roles roles: deletionTarget.roles
}} }}

View File

@@ -4631,6 +4631,19 @@ export type Database = {
Args: { _user_id: string } Args: { _user_id: string }
Returns: Json Returns: Json
} }
get_users_with_emails: {
Args: never
Returns: {
avatar_url: string
banned: boolean
created_at: string
display_name: string
email: string
id: string
user_id: string
username: string
}[]
}
get_version_diff: { get_version_diff: {
Args: { Args: {
p_entity_type: string p_entity_type: string

View File

@@ -0,0 +1,43 @@
-- Create RPC function to get users with emails for admin/superuser
CREATE OR REPLACE FUNCTION public.get_users_with_emails()
RETURNS TABLE (
id uuid,
user_id uuid,
username text,
email text,
display_name text,
avatar_url text,
banned boolean,
created_at timestamptz
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public', 'auth'
AS $$
BEGIN
-- Check if caller is superuser or admin
IF NOT EXISTS (
SELECT 1 FROM public.user_roles
WHERE user_roles.user_id = auth.uid()
AND role IN ('superuser', 'admin')
) THEN
RAISE EXCEPTION 'Access denied: requires admin or superuser role'
USING ERRCODE = '42501';
END IF;
-- Return profiles with emails from auth.users
RETURN QUERY
SELECT
p.id,
p.user_id,
p.username,
COALESCE(au.email, 'unknown@email.com') as email,
p.display_name,
p.avatar_url,
p.banned,
p.created_at
FROM public.profiles p
LEFT JOIN auth.users au ON au.id = p.user_id
ORDER BY p.created_at DESC;
END;
$$;

View File

@@ -34,19 +34,32 @@ export async function setupTestUser(
throw new Error('Service role key not configured'); throw new Error('Service role key not configured');
} }
// Create user in auth // Check if user already exists
const { data: authData, error: authError } = await supabaseAdmin.auth.admin.createUser({ const { data: existingUsers } = await supabaseAdmin.auth.admin.listUsers();
email, const existingUser = existingUsers?.users.find(u => u.email === email);
password,
email_confirm: true,
});
if (authError) throw authError; let userId: string;
if (!authData.user) throw new Error('User creation failed');
const userId = authData.user.id; if (existingUser) {
// User exists - use their ID
userId = existingUser.id;
console.log(` Using existing test user: ${email}`);
} else {
// User doesn't exist - create new one
const { data: authData, error: authError } = await supabaseAdmin.auth.admin.createUser({
email,
password,
email_confirm: true,
});
// Create profile if (authError) throw authError;
if (!authData.user) throw new Error('User creation failed');
userId = authData.user.id;
console.log(`✓ Created new test user: ${email}`);
}
// Create or update profile (ensures correct role and is_test_data flag)
const { error: profileError } = await supabaseAdmin const { error: profileError } = await supabaseAdmin
.from('profiles') .from('profiles')
.upsert({ .upsert({