Fix profile privacy and simplify code

This commit is contained in:
gpt-engineer-app[bot]
2025-10-14 18:11:10 +00:00
parent 85c79ad511
commit 6698ee9a29
6 changed files with 100 additions and 217 deletions

View File

@@ -10,25 +10,47 @@ export function useProfile(userId: string | undefined) {
queryFn: async () => {
if (!userId) return null;
console.log('[useProfile] Fetching profile for userId:', userId);
console.log('[useProfile] Fetching filtered profile for userId:', userId);
const { data, error } = await supabase
.from('profiles')
.select('*, location:locations(*)')
.eq('user_id', userId)
.maybeSingle();
// Get current viewer ID
const { data: { user } } = await supabase.auth.getUser();
const viewerId = user?.id || null;
// Use get_filtered_profile RPC for privacy-aware field filtering
const { data, error } = await supabase.rpc('get_filtered_profile', {
_profile_user_id: userId,
_viewer_id: viewerId
});
if (error) {
console.error('[useProfile] Error:', error);
throw error;
}
console.log('[useProfile] Profile loaded:', {
username: data?.username,
avatar_url: data?.avatar_url
if (!data) return null;
// Type assertion since we know the structure from the RPC function
const profileData = data as unknown as Profile;
// Fetch location separately if location_id is present and visible
if (profileData.location_id) {
const { data: location } = await supabase
.from('locations')
.select('*')
.eq('id', profileData.location_id)
.single();
if (location) {
profileData.location = location;
}
}
console.log('[useProfile] Filtered profile loaded:', {
username: profileData.username,
has_avatar: !!profileData.avatar_url
});
return data as Profile;
return profileData;
},
enabled: !!userId,
staleTime: 5 * 60 * 1000, // 5 minutes

View File

@@ -1,94 +0,0 @@
import { useState, useEffect } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { useAuth } from '@/hooks/useAuth';
interface ProfileFieldAccess {
[fieldName: string]: boolean;
}
export function useProfileFieldAccess(profileUserId: string | null | undefined) {
const { user } = useAuth();
const [fieldAccess, setFieldAccess] = useState<ProfileFieldAccess>({});
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!profileUserId) {
setLoading(false);
return;
}
checkFieldAccess();
}, [profileUserId, user?.id]);
const checkFieldAccess = async () => {
if (!profileUserId || !user?.id) {
setLoading(false);
return;
}
try {
setLoading(true);
// Fields that might need privacy checking
const fieldsToCheck = [
'date_of_birth',
'personal_location',
'location_id',
'preferred_pronouns',
'home_park_id',
'bio',
'avatar_url',
'avatar_image_id'
];
const accessChecks: ProfileFieldAccess = {};
// Check each field individually using our security definer function
for (const field of fieldsToCheck) {
const { data, error } = await supabase.rpc('can_view_profile_field', {
_viewer_id: user.id,
_profile_user_id: profileUserId,
_field_name: field
});
if (error) {
console.error(`Error checking access for field ${field}:`, error);
accessChecks[field] = false;
} else {
accessChecks[field] = data === true;
}
}
setFieldAccess(accessChecks);
} catch (error) {
console.error('Error checking field access:', error);
// Default to denying access on error
setFieldAccess({});
} finally {
setLoading(false);
}
};
const canViewField = (fieldName: string): boolean => {
if (!profileUserId || !user?.id) {
return false;
}
// Users can always see their own fields
if (user.id === profileUserId) {
return true;
}
return fieldAccess[fieldName] || false;
};
const refresh = () => {
checkFieldAccess();
};
return {
canViewField,
loading,
refresh
};
}