feat: implement group-based access control (Admin, Standard_User, Leadership, Read_Only)
- Add user_group migration and created_by column migration - Replace requireRole middleware with requireGroup - Update all backend routes to use group-based authorization - Add Standard_User conditional delete with ownership, state, and compliance checks - Add cascade impact check for CVE deletes - Update AuthContext with group-based permission helpers - Update all frontend components for group-based rendering - Update UserManagement UI with group dropdown, confirmation dialogs, self-demotion prevention
This commit is contained in:
@@ -19,17 +19,26 @@ export default function UserMenu({ onManageUsers, onAuditLog }) {
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
|
||||
const getRoleBadgeColor = (role) => {
|
||||
switch (role) {
|
||||
case 'admin':
|
||||
const getGroupBadgeColor = (group) => {
|
||||
switch (group) {
|
||||
case 'Admin':
|
||||
return 'bg-red-100 text-red-800';
|
||||
case 'editor':
|
||||
case 'Standard_User':
|
||||
return 'bg-blue-100 text-blue-800';
|
||||
case 'Leadership':
|
||||
return 'bg-purple-100 text-purple-800';
|
||||
case 'Read_Only':
|
||||
return 'bg-gray-100 text-gray-800';
|
||||
default:
|
||||
return 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
};
|
||||
|
||||
const formatGroupName = (group) => {
|
||||
if (!group) return '';
|
||||
return group.replace(/_/g, ' ');
|
||||
};
|
||||
|
||||
const handleLogout = async () => {
|
||||
setIsOpen(false);
|
||||
await logout();
|
||||
@@ -62,7 +71,7 @@ export default function UserMenu({ onManageUsers, onAuditLog }) {
|
||||
</div>
|
||||
<div className="text-left hidden sm:block">
|
||||
<p className="text-sm font-medium text-gray-900">{user.username}</p>
|
||||
<p className="text-xs text-gray-500 capitalize">{user.role}</p>
|
||||
<p className="text-xs text-gray-500">{formatGroupName(user.group)}</p>
|
||||
</div>
|
||||
<ChevronDown className={`w-4 h-4 text-gray-500 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
|
||||
</button>
|
||||
@@ -72,8 +81,8 @@ export default function UserMenu({ onManageUsers, onAuditLog }) {
|
||||
<div className="px-4 py-3 border-b border-gray-100">
|
||||
<p className="text-sm font-medium text-gray-900">{user.username}</p>
|
||||
<p className="text-sm text-gray-500">{user.email}</p>
|
||||
<span className={`inline-block mt-2 px-2 py-1 rounded text-xs font-medium ${getRoleBadgeColor(user.role)}`}>
|
||||
{user.role.charAt(0).toUpperCase() + user.role.slice(1)}
|
||||
<span className={`inline-block mt-2 px-2 py-1 rounded text-xs font-medium ${getGroupBadgeColor(user.group)}`}>
|
||||
{formatGroupName(user.group)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user