Added isAdmin tag for users

This commit is contained in:
2026-05-04 21:03:50 -06:00
parent fc7c821d0f
commit a8ee92afc8
6 changed files with 42 additions and 24 deletions

1
.gitignore vendored
View File

@@ -67,3 +67,4 @@ dmypy.json
node_modules/ node_modules/
*.pem *.pem
credentials.json credentials.json
migrations/

View File

@@ -16,3 +16,4 @@ class User:
numero_reportes: int = 0 numero_reportes: int = 0
url_foto_perfil: Optional[str] = None url_foto_perfil: Optional[str] = None
biografia: Optional[str] = None biografia: Optional[str] = None
is_admin: bool = False # Indica si el usuario tiene permisos de administrador

View File

@@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, Float, DateTime from sqlalchemy import Column, Integer, String, Float, DateTime, Boolean
from infrastructure.adapters.persistence.db import Base from infrastructure.adapters.persistence.db import Base
from datetime import datetime from datetime import datetime
@@ -17,3 +17,4 @@ class UserModel(Base):
numero_reportes = Column(Integer, default=0, nullable=False) numero_reportes = Column(Integer, default=0, nullable=False)
url_foto_perfil = Column(String(500), nullable=True) url_foto_perfil = Column(String(500), nullable=True)
biografia = Column(String(1000), nullable=True) biografia = Column(String(1000), nullable=True)
is_admin = Column(Boolean, default=False, nullable=False, index=True) # Permisos de administrador

View File

@@ -26,7 +26,8 @@ class UserRepositorySQL(UserRepository):
calificacion=user.calificacion, calificacion=user.calificacion,
numero_reportes=user.numero_reportes, numero_reportes=user.numero_reportes,
url_foto_perfil=user.url_foto_perfil, url_foto_perfil=user.url_foto_perfil,
biografia=user.biografia biografia=user.biografia,
is_admin=user.is_admin
) )
self.db.add(db_user) self.db.add(db_user)
self.db.commit() self.db.commit()
@@ -160,5 +161,6 @@ class UserRepositorySQL(UserRepository):
calificacion=db_user.calificacion, calificacion=db_user.calificacion,
numero_reportes=db_user.numero_reportes, numero_reportes=db_user.numero_reportes,
url_foto_perfil=db_user.url_foto_perfil, url_foto_perfil=db_user.url_foto_perfil,
biografia=db_user.biografia biografia=db_user.biografia,
is_admin=db_user.is_admin
) )

View File

@@ -1,5 +1,5 @@
"""Endpoints de moderación para gestión de reportes, cuentas y usuarios""" """Endpoints de moderación para gestión de reportes, cuentas y usuarios"""
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException, Depends
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from infrastructure.api.moderations.schemas import ( from infrastructure.api.moderations.schemas import (
DeleteReportRequest, DeleteReportRequest,
@@ -9,6 +9,7 @@ from infrastructure.api.moderations.schemas import (
ReviewContentRequest, ReviewContentRequest,
ModerationActionResponse ModerationActionResponse
) )
from infrastructure.api.auth import get_current_admin_user
from application.services.moderation_services import ( from application.services.moderation_services import (
DeleteReportUseCase, DeleteReportUseCase,
CloseAccountUseCase, CloseAccountUseCase,
@@ -19,6 +20,7 @@ from application.services.moderation_services import (
from infrastructure.adapters.persistence.mongodb import mongodb from infrastructure.adapters.persistence.mongodb import mongodb
from infrastructure.adapters.persistence.db import get_db from infrastructure.adapters.persistence.db import get_db
from infrastructure.adapters.moderation_repository_mongo import ModerationRepositoryMongo from infrastructure.adapters.moderation_repository_mongo import ModerationRepositoryMongo
from domain.users import User
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
import logging import logging
@@ -32,11 +34,13 @@ moderation_repo = ModerationRepositoryMongo()
@router.post("/reports/delete", response_model=ModerationActionResponse) @router.post("/reports/delete", response_model=ModerationActionResponse)
async def delete_report(request: DeleteReportRequest): async def delete_report(
request: DeleteReportRequest,
current_admin: User = Depends(get_current_admin_user)
):
""" """
Eliminar un reporte como moderador Eliminar un reporte como moderador (requiere permisos de admin)
- **moderator_id**: ID del moderador que ejecuta la acción
- **report_id**: ID del reporte a eliminar - **report_id**: ID del reporte a eliminar
- **reason**: Razón de la eliminación (mínimo 5 caracteres) - **reason**: Razón de la eliminación (mínimo 5 caracteres)
- **description**: Descripción adicional (opcional) - **description**: Descripción adicional (opcional)
@@ -44,7 +48,7 @@ async def delete_report(request: DeleteReportRequest):
try: try:
use_case = DeleteReportUseCase(moderation_repo) use_case = DeleteReportUseCase(moderation_repo)
result = use_case.execute( result = use_case.execute(
moderator_id=request.moderator_id, moderator_id=current_admin.user_id,
report_id=request.report_id, report_id=request.report_id,
reason=request.reason, reason=request.reason,
description=request.description description=request.description
@@ -61,11 +65,13 @@ async def delete_report(request: DeleteReportRequest):
@router.post("/accounts/close", response_model=ModerationActionResponse) @router.post("/accounts/close", response_model=ModerationActionResponse)
async def close_account(request: CloseAccountRequest): async def close_account(
request: CloseAccountRequest,
current_admin: User = Depends(get_current_admin_user)
):
""" """
Cerrar una cuenta de usuario Cerrar una cuenta de usuario (requiere permisos de admin)
- **moderator_id**: ID del moderador
- **user_id**: ID del usuario cuya cuenta cerrar - **user_id**: ID del usuario cuya cuenta cerrar
- **reason**: Razón del cierre (mínimo 5 caracteres) - **reason**: Razón del cierre (mínimo 5 caracteres)
- **description**: Descripción adicional (opcional) - **description**: Descripción adicional (opcional)
@@ -74,7 +80,7 @@ async def close_account(request: CloseAccountRequest):
try: try:
use_case = CloseAccountUseCase(moderation_repo) use_case = CloseAccountUseCase(moderation_repo)
result = use_case.execute( result = use_case.execute(
moderator_id=request.moderator_id, moderator_id=current_admin.user_id,
user_id=request.user_id, user_id=request.user_id,
reason=request.reason, reason=request.reason,
description=request.description, description=request.description,
@@ -92,11 +98,13 @@ async def close_account(request: CloseAccountRequest):
@router.post("/users/ban", response_model=ModerationActionResponse) @router.post("/users/ban", response_model=ModerationActionResponse)
async def ban_user(request: BanUserRequest): async def ban_user(
request: BanUserRequest,
current_admin: User = Depends(get_current_admin_user)
):
""" """
Banear a un usuario Banear a un usuario (requiere permisos de admin)
- **moderator_id**: ID del moderador
- **user_id**: ID del usuario a banear - **user_id**: ID del usuario a banear
- **reason**: Razón del ban (mínimo 5 caracteres) - **reason**: Razón del ban (mínimo 5 caracteres)
- **duration_days**: Duración del ban en días (None para permanente) - **duration_days**: Duración del ban en días (None para permanente)
@@ -105,7 +113,7 @@ async def ban_user(request: BanUserRequest):
try: try:
use_case = BanUserUseCase(moderation_repo) use_case = BanUserUseCase(moderation_repo)
result = use_case.execute( result = use_case.execute(
moderator_id=request.moderator_id, moderator_id=current_admin.user_id,
user_id=request.user_id, user_id=request.user_id,
reason=request.reason, reason=request.reason,
duration_days=request.duration_days, duration_days=request.duration_days,
@@ -123,11 +131,13 @@ async def ban_user(request: BanUserRequest):
@router.post("/users/warn", response_model=ModerationActionResponse) @router.post("/users/warn", response_model=ModerationActionResponse)
async def warn_user(request: WarnUserRequest): async def warn_user(
request: WarnUserRequest,
current_admin: User = Depends(get_current_admin_user)
):
""" """
Advertir a un usuario Advertir a un usuario (requiere permisos de admin)
- **moderator_id**: ID del moderador
- **user_id**: ID del usuario a advertir - **user_id**: ID del usuario a advertir
- **reason**: Razón de la advertencia (mínimo 5 caracteres) - **reason**: Razón de la advertencia (mínimo 5 caracteres)
- **description**: Descripción adicional (opcional) - **description**: Descripción adicional (opcional)
@@ -135,7 +145,7 @@ async def warn_user(request: WarnUserRequest):
try: try:
use_case = WarnUserUseCase(moderation_repo) use_case = WarnUserUseCase(moderation_repo)
result = use_case.execute( result = use_case.execute(
moderator_id=request.moderator_id, moderator_id=current_admin.user_id,
user_id=request.user_id, user_id=request.user_id,
reason=request.reason, reason=request.reason,
description=request.description description=request.description
@@ -152,11 +162,13 @@ async def warn_user(request: WarnUserRequest):
@router.post("/content/review", response_model=ModerationActionResponse) @router.post("/content/review", response_model=ModerationActionResponse)
async def review_content(request: ReviewContentRequest): async def review_content(
request: ReviewContentRequest,
current_admin: User = Depends(get_current_admin_user)
):
""" """
Revisar y actuar sobre contenido reportado Revisar y actuar sobre contenido reportado (requiere permisos de admin)
- **moderator_id**: ID del moderador
- **report_id**: ID del reporte a revisar - **report_id**: ID del reporte a revisar
- **action**: Acción a tomar (approve, reject, needs_more_info) - **action**: Acción a tomar (approve, reject, needs_more_info)
- **reason**: Razón de la decisión (opcional) - **reason**: Razón de la decisión (opcional)
@@ -165,7 +177,7 @@ async def review_content(request: ReviewContentRequest):
try: try:
use_case = ReviewContentUseCase(moderation_repo) use_case = ReviewContentUseCase(moderation_repo)
result = use_case.execute( result = use_case.execute(
moderator_id=request.moderator_id, moderator_id=current_admin.user_id,
report_id=request.report_id, report_id=request.report_id,
action=request.action, action=request.action,
reason=request.reason, reason=request.reason,

View File

@@ -46,6 +46,7 @@ class UserResponse(BaseModel):
numero_reportes: int numero_reportes: int
url_foto_perfil: Optional[str] url_foto_perfil: Optional[str]
biografia: Optional[str] biografia: Optional[str]
is_admin: bool
class Config: class Config:
from_attributes = True from_attributes = True