feat: Add asesor role with reports-only access - backend v1.0.10, frontend v1.0.16

This commit is contained in:
2025-11-20 16:23:52 -03:00
parent 5d2a96553e
commit 570cdb6739
4 changed files with 30 additions and 22 deletions

View File

@@ -1284,8 +1284,8 @@ def get_dashboard_data(
db: Session = Depends(get_db) db: Session = Depends(get_db)
): ):
"""Obtener datos del dashboard de informes""" """Obtener datos del dashboard de informes"""
if current_user.role != "admin": if current_user.role not in ["admin", "asesor"]:
raise HTTPException(status_code=403, detail="Solo administradores pueden acceder a reportes") raise HTTPException(status_code=403, detail="No tienes permisos para acceder a reportes")
# Construir query base # Construir query base
query = db.query(models.Inspection) query = db.query(models.Inspection)
@@ -1531,8 +1531,8 @@ def get_inspections_report(
db: Session = Depends(get_db) db: Session = Depends(get_db)
): ):
"""Obtener lista de inspecciones con filtros""" """Obtener lista de inspecciones con filtros"""
if current_user.role != "admin": if current_user.role not in ["admin", "asesor"]:
raise HTTPException(status_code=403, detail="Solo administradores pueden acceder a reportes") raise HTTPException(status_code=403, detail="No tienes permisos para acceder a reportes")
# Query base con select_from explícito # Query base con select_from explícito
query = db.query( query = db.query(

View File

@@ -10,7 +10,7 @@ class User(Base):
username = Column(String(50), unique=True, index=True, nullable=False) username = Column(String(50), unique=True, index=True, nullable=False)
email = Column(String(100), unique=True, index=True) email = Column(String(100), unique=True, index=True)
password_hash = Column(String(255), nullable=False) password_hash = Column(String(255), nullable=False)
role = Column(String(20), nullable=False) # admin, mechanic role = Column(String(20), nullable=False) # admin, mechanic, asesor
full_name = Column(String(100)) full_name = Column(String(100))
is_active = Column(Boolean, default=True) is_active = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now()) created_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -20,7 +20,7 @@ services:
retries: 5 retries: 5
backend: backend:
image: dymai/syntria-backend:1.0.9 image: dymai/syntria-backend:1.0.10
container_name: syntria-backend-prod container_name: syntria-backend-prod
restart: always restart: always
depends_on: depends_on:
@@ -38,7 +38,7 @@ services:
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4 command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
frontend: frontend:
image: dymai/syntria-frontend:1.0.15 image: dymai/syntria-frontend:1.0.16
container_name: syntria-frontend-prod container_name: syntria-frontend-prod
restart: always restart: always
depends_on: depends_on:

View File

@@ -67,20 +67,26 @@ export default function Sidebar({ user, activeTab, setActiveTab, sidebarOpen, se
{sidebarOpen && <span>Usuarios</span>} {sidebarOpen && <span>Usuarios</span>}
</button> </button>
</li> </li>
<li> </>
<button )}
onClick={() => setActiveTab('reports')} {(user.role === 'admin' || user.role === 'asesor') && (
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${ <li>
activeTab === 'reports' <button
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg' onClick={() => setActiveTab('reports')}
: 'text-indigo-200 hover:bg-indigo-900/50' className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
}`} activeTab === 'reports'
title={!sidebarOpen ? 'Reportes' : ''} ? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
> : 'text-indigo-200 hover:bg-indigo-900/50'
<span className="text-xl">📊</span> }`}
{sidebarOpen && <span>Reportes</span>} title={!sidebarOpen ? 'Reportes' : ''}
</button> >
</li> <span className="text-xl">📊</span>
{sidebarOpen && <span>Reportes</span>}
</button>
</li>
)}
{user.role === 'admin' && (
<>
<li> <li>
<button <button
onClick={() => setActiveTab('api-tokens')} onClick={() => setActiveTab('api-tokens')}
@@ -123,7 +129,9 @@ export default function Sidebar({ user, activeTab, setActiveTab, sidebarOpen, se
{sidebarOpen && ( {sidebarOpen && (
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate text-white">{user.full_name || user.username}</p> <p className="text-sm font-medium truncate text-white">{user.full_name || user.username}</p>
<p className="text-xs text-indigo-300">{user.role === 'admin' ? '👑 Admin' : '🔧 Mecánico'}</p> <p className="text-xs text-indigo-300">
{user.role === 'admin' ? '👑 Admin' : user.role === 'asesor' ? '📊 Asesor' : '🔧 Mecánico'}
</p>
</div> </div>
)} )}
</div> </div>