feat: complete fine-grained RBAC rules across all roles
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m52s

- Restricted Agent view to own dashboard and hid management tabs.

- Allowed Managers to create teams and members but restricted them from editing roles or emails.

- Allowed Admins to update their own email via profile.

- Protected Admin roles from being modified by anyone other than Super Admins.
This commit is contained in:
Cauê Faleiros
2026-03-06 13:27:43 -03:00
parent 2e766bd197
commit 38eb55793f
6 changed files with 66 additions and 43 deletions

View File

@@ -232,10 +232,19 @@ export const TeamManagement: React.FC = () => {
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-bold text-zinc-500 dark:text-dark-muted uppercase mb-1 block">Função</label>
<select value={formData.role} onChange={e => setFormData({...formData, role: e.target.value as any})} className="w-full bg-white dark:bg-dark-input border border-zinc-200 dark:border-dark-border p-3 rounded-lg text-sm text-zinc-900 dark:text-dark-text">
<select
value={formData.role}
onChange={e => setFormData({...formData, role: e.target.value as any})}
className="w-full bg-white dark:bg-dark-input border border-zinc-200 dark:border-dark-border p-3 rounded-lg text-sm text-zinc-900 dark:text-dark-text disabled:bg-zinc-50 dark:disabled:bg-dark-bg/50 dark:disabled:text-dark-muted"
disabled={
(currentUser?.role === 'manager') ||
(editingUser?.role === 'admin' && currentUser?.role !== 'super_admin') ||
(editingUser?.role === 'super_admin' && currentUser?.role !== 'super_admin')
}
>
<option value="agent">Agente</option>
<option value="manager">Gerente</option>
<option value="admin">Admin</option>
{currentUser?.role !== 'manager' && <option value="admin">Admin</option>}
</select>
</div>
<div>

View File

@@ -14,6 +14,7 @@ export const UserProfile: React.FC = () => {
const [name, setName] = useState('');
const [bio, setBio] = useState('');
const [email, setEmail] = useState('');
useEffect(() => {
const fetchUserAndTenant = async () => {
@@ -25,6 +26,7 @@ export const UserProfile: React.FC = () => {
setUser(fetchedUser);
setName(fetchedUser.name);
setBio(fetchedUser.bio || '');
setEmail(fetchedUser.email);
// Fetch tenant info
const tenants = await getTenants();
@@ -85,10 +87,10 @@ export const UserProfile: React.FC = () => {
setIsSuccess(false);
try {
const success = await updateUser(user.id, { name, bio });
const success = await updateUser(user.id, { name, bio, email });
if (success) {
setIsSuccess(true);
setUser({ ...user, name, bio });
setUser({ ...user, name, bio, email });
setTimeout(() => setIsSuccess(false), 3000);
} else {
alert('Erro ao salvar alterações no servidor.');
@@ -107,6 +109,8 @@ export const UserProfile: React.FC = () => {
const displayAvatar = user.avatar_url
? (user.avatar_url.startsWith('http') ? user.avatar_url : `${backendUrl}${user.avatar_url}`)
: `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=random`;
const canEditEmail = user.role === 'admin' || user.role === 'super_admin';
return (
<div className="max-w-4xl mx-auto space-y-6 pb-12 transition-colors duration-300">
@@ -213,12 +217,17 @@ export const UserProfile: React.FC = () => {
<input
type="email"
id="email"
value={user.email}
disabled
className="block w-full pl-10 pr-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded-lg bg-zinc-50 dark:bg-zinc-900/50 text-zinc-500 dark:text-zinc-500 cursor-not-allowed sm:text-sm"
value={email}
onChange={(e) => setEmail(e.target.value)}
disabled={!canEditEmail}
className={`block w-full pl-10 pr-3 py-2 border border-zinc-200 dark:border-zinc-800 rounded-lg sm:text-sm transition-all ${
!canEditEmail
? 'bg-zinc-50 dark:bg-zinc-900/50 text-zinc-500 dark:text-zinc-500 cursor-not-allowed'
: 'bg-white dark:bg-zinc-950 text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 dark:placeholder-zinc-600 focus:outline-none focus:ring-2 focus:ring-brand-yellow/20 focus:border-brand-yellow'
}`}
/>
</div>
<p className="text-xs text-zinc-400 dark:text-zinc-500 mt-1">Contate o admin para alterar o e-mail.</p>
{!canEditEmail && <p className="text-xs text-zinc-400 dark:text-zinc-500 mt-1">Contate o admin para alterar o e-mail.</p>}
</div>
</div>