Reputation: 1
I'm having an issue when limiting the data assigned to each user. I'm developing the app with Next.js and Supabase. I have a table called BR hosted on Supabase with its primary key being cod_grupo, and in that row, I have all the information. In the last column, it's called "email," and within each record, I have an array of text with the names of the people who can access it. I have created a policy in Supabase to only allow reading the cod_grupo that has an email in that array.
alter policy "email.policy" on "public"."BR" to public using:
( (auth.email() = ANY (email))
);
Here I have my view which is inside the "app" folder and in turn inside the "protected" folder named page.tsx:
import DeployButton from "@/components/DeployButton";
import AuthButton from "@/components/AuthButton";
import { createClient } from "@/utils/supabase/server";
import Header from "@/components/Header";
import { redirect } from "next/navigation";
import SearchBarIndex from "@/components/SearchBarIndex";
import "../globals.css";
export default async function ProtectedPage() {
const supabase = createClient();
const { data, error } = await supabase.auth.getUser();
let groups = [];
if (error || !data?.user) {
redirect("/login");
} else {const { data: groups, error: groupsError } = await supabase
.from("BR")
.select("COD_GRUPO");
if (groupsError) {
console.error("Error fetching groups:", groupsError.message);
} else {
console.log("COD_GRUPO a los que el usuario tiene acceso:", groups);
}
}
return (
<div className="flex justify-center items-center">
<div className="flex-m1 w-full flex flex-col gap-20 items-center pt-28">
<div className="animate-in flex-1 flex flex-col gap-12 opacity-0 max-w-4xl px-3 py-10">
<Header />
<SearchBarIndex loggedInUser={data.user} CODG={groups} />
<main className="flex-1 flex flex-col gap-6">
<h2 className="font-vivo text-xs text-[#B1B1B1]">
Hola {data.user.email} Use a barra de pesquisa para acessar suas
contas por CÓDIGO DE GRUPO ou por nombre de empresa Y puedes
acceder a la información de tu grupo económico
</h2>
</main>
</div>
<footer className="text-[#B1B1B1] flex justify-center text-center text-xs pb-10">
<p>
Powered by <a>Vivo</a>
</p>
</footer>
</div>
</div>
);
}
This view is rendered on the server side and this is the "SearchBarIndex" component that is rendered on the client side:
'use client'
import React, { useState, useEffect, useCallback } from 'react';
import { useRouter } from 'next/navigation';
import { supabase } from '../utils/supabase/supabaseClient';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
// Call toast.configure in the main component of your application
export default function SearchBarIndex({loggedInUser, CODG}) {
console.log("these are the cods", CODG)
console.log("these are the users", loggedInUser)
const [user, setUser] = useState(loggedInUser); // Pass Props for authenticated user recognition
const [error, setError] = useState(null);
const [searchTerm, setSearchTerm] = useState('');
const [suggestions, setSuggestions] = useState([]);
const router = useRouter();
useEffect(() => {
console.log('Authenticated user from prop:', user.email);
console.log('access group code', CODG);
}, [user, CODG]);
const handleSearch = async () => {
// Extract the GROUP CODE from the searchTerm
const [searchGroupCode] = searchTerm.split(' - ');
// Check if the searched GROUP CODE is in the list of group codes the user has access to
if (!CODG.includes(searchGroupCode)) {
toast.error('You do not have access to this group');
return;
}
// If the user has access, navigate to the corresponding page
router.push(`/notes/${searchGroupCode}`);
};
const handleChange = async (e) => {
const value = e.target.value;
setSearchTerm(value);
if (value.trim() === '') {
setSuggestions([]);
return;
}
try {
// Get the group codes the user has access to
const { data: userGroupsData, error: userGroupsError } = await supabase
.from('BR')
.select('COD_GRUPO')
.contains('email', [user.email]);
console.log('it is me', userGroupsData);
if (userGroupsError) throw userGroupsError;
const { data, error } = await supabase
.from('BR')
.select('COD_GRUPO, GRUPO_ECONOMICO')
.in('COD_GRUPO', userGroupsData.map(item => item.COD_GRUPO))
.or(`COD_GRUPO.ilike.%${value}%,GRUPO_ECONOMICO.ilike.%${value}%`)
.limit(5);
if (error) throw error;
console.log('access GROUP CODE', data);
setSuggestions(data.map(item => `${item.COD_GRUPO} - ${item.GRUPO_ECONOMICO}`));
} catch (error) {
console.error("Error fetching suggestions:", error.message);
}
};
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
handleSearch();
}
};
const selectSuggestion = (suggestion) => {
const [groupCode] = suggestion.split(' - ');
setSearchTerm(suggestion);
setSuggestions([]);
// Redirect the user to the page.tsx within the [GROUP CODE] folder
router.push(`/notes/${groupCode}`);
};
return (
<div className="flex flex-col items- w-full">
<ToastContainer />
<input
type="text"
placeholder="Search..."
className="px-4 py-1 border rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 font-vivo text-gray-500 text-sm"
value={searchTerm}
onChange={handleChange}
onKeyDown={(e) => e.key === 'Enter' && setSearchTerm(e.target.value)}
/>
{error && <div className="text-red-500">{error}</div>}
{suggestions.length > 0 && (
<ul className="absolute z-10 w-full bg-white shadow-md max-h-60 overflow-auto mt-12 text-gray-500 text-sm">
{suggestions.map((suggestion, index) => (
<li
key={index}
className="p-2 hover:bg-gray-100 cursor-pointer text-gray-500 text-sm"
onClick={() => selectSuggestion(suggestion)}
>
{suggestion}
</li>
))}
</ul>
)}
</div>
);
}
The strange thing is that when I leave the policy open in Supabase so that everyone can see the data, the autocomplete works perfectly. But when I restrict it to email users it doesn't respond, nor does the autocomplete work. In page.tsx I do the console.log of the CODs it receives and it returns the array with the objects but it does not do the console.log in the browser console. Thank you very much in advance
I want the records to be rendered in the search bar to which the user has access, and I want the search bar to be able to perform autocompletion just like when I have the policy open to any user. Also, I want to prevent access by pasting the record into the navigation bar. However, the autocompletion and redirection to the page are not working.
Upvotes: 0
Views: 158