Skip to content

Repository files navigation

EFI2_python_2025: API REST de Blog/Foro con Flask y SQLAlchemy

Este proyecto es una API RESTful desarrollada con Flask. Utiliza autenticación JWT, autorización basada en roles (RBAC) y operaciones CRUD con eliminación lógica.

Integrantes:

Abataneo, Pablo: @pablo-itec

Cabrera, Ulises: @Ulicrack


Dependencias de Python que requiere el proyecto:

  • Flask==3.0.0
  • Flask-SQLAlchemy==3.1.1
  • Flask-JWT-Extended==4.4.4
  • Flask-CORS==4.0.0
  • Flask-Migrate==4.0.5
  • Marshmallow==3.21.1
  • passlib[bcrypt]==1.7.4
  • pymysql==1.1.0

Arquitectura y Nota Importante (Blueprint vs. MethodView)

Se implementó una arquitectura de tres capas (Vistas, Servicios y Repositorios) para garantizar la separación de responsabilidades y la modularidad del código.

Nota sobre el diseño: Elegmos utilizar Blueprints en lugar de MethodView porque, si bien MethodView es ideal para estructurar operaciones CRUD de un recurso individual de forma orientada a objetos, Blueprint ofrece una estrategia de modularización superior para todo el proyecto. Permite segmentar el código por áreas funcionales (ej. autenticación, posts, usuarios) en archivos separados, manteniendo la aplicación principal ligera y garantizando que el proyecto sea escalable y fácil de mantener.


Instrucciones de Instalación

1. Requisitos Previos

  • Python 3.8+
  • uv instalado. Si no lo tienes, instálalo globalmente con pip install uv.
  • MySQL instalado y corriendo (o MariaDB).
  • Crear la base de datos llamada py_efi2_db.

2. Configuración del Entorno

# 1. Clona el repositorio
git clone https://github.com/Ulicrack/EFI2_python_2025.git
cd EFI2_python_2025

# 2. Crea el entorno virtual con uv (esto también lo activa automáticamente en muchas shells)
uv venv

# 3. Instala y sincroniza las dependencias desde requirements.txt
uv sync

# Si tu shell no activó automáticamente el entorno, hazlo manualmente:
source .venv/bin/activate  # En Linux/macOS
# .\venv\Scripts\activate  # En Windows/PowerShell

3. Configuración de la Base de Datos

Asegúrate de que las credenciales de MySQL en app.py o config_vars.py coincidan con tu entorno.

4. Ejecución

# Ejecuta el script principal
python app.py

La API estará disponible en http://127.0.0.1:5000/.

Credenciales de Prueba

Utiliza estas credenciales para obtener tokens en el endpoint /login.

    Rol     |        Email          | Contraseña
Admin	    | lautaro@admin.com	    | lautaropass
Moderator   | maria@mod.com         | mariapass
User	    | sofia@user.com	    | sofiapass

(Las contraseñas hasheadas para estos usuarios deben ser inyectadas en la base de datos con un script SQL)

Documentación de Endpoints:

Módulo   |	Método   |	       Ruta          |	          Descripción              |	Acceso
Auth	 |  POST	 | /register             |	Crea un nuevo usuario.             |	Público
Auth	 |  POST	 | /login	             |  Genera JWT de acceso.	           |    Público
Posts	 |  GET	     | /posts/active         |	Lista posts activos.               |	Público
Posts	 |  POST     | /posts/               |	Crea un nuevo post.                |	Autenticado
Posts	 |  PUT      | /posts/<id>           |	Actualiza post.                    |	Autor / Mod / Admin
Posts	 |  DELETE   | /posts/<id>           |	Elimina post (Soft Delete).        |	Autor / Mod / Admin
Comments |	POST     | /posts/<id>/comments/ |	Crea un comentario en un post.     |	Autenticado
Comments |	PUT      | /comments/<id>        |	Actualiza comentario.              |	Autor / Mod / Admin
Users    |	GET      | /users/               |	Lista todos los usuarios.          |	Admin
Users    |	PUT      | /users/<id>           |	Actualiza perfil (username/email). |	Propietario / Admin
Users    |	PUT      | /users/<id>/role      |	Cambia el rol de un usuario.       |	Admin
Stats    |	GET      | /stats/               |	Obtiene estadísticas del sistema.  |	Admin / Mod

3. Base de Datos (Script SQL de Creación y Datos de Prueba)

db_setup.sql (Migraciones y Seeding)

Dado que usas Flask-Migrate, el enfoque ideal es:

    Crear Tablas: Ejecuta la migración inicial:

    # Inicializar migraciones
    flask db init
    # Crear la primera migración
    flask db migrate -m "Initial models creation"
    # Aplicar la migración a la DB
    flask db upgrade

Datos de Prueba (Seeding): Aquí se usa SQL directo para insertar los usuarios y roles base. Necesitarás los hashes generados por hash_generator.py.

-- db_seeding.sql
  1. INSERTAR CATEGORÍAS DE PRUEBA
INSERT INTO categoria (id, name) VALUES (1, 'Tecnología');
INSERT INTO categoria (id, name) VALUES (2, 'Deportes');
INSERT INTO categoria (id, name) VALUES (3, 'Noticias');
  1. INSERTAR USUARIOS DE PRUEBA (User)
-- NOTA: Los IDs deben coincidir con las FK en user_credentials

INSERT INTO user (id, name, email, is_active) VALUES (1, 'LautaroAdmin', 'lautaro@admin.com', 1);
INSERT INTO user (id, name, email, is_active) VALUES (2, 'MariaMod', 'maria@mod.com', 1);
INSERT INTO user (id, name, email, is_active) VALUES (3, 'SofiaUser', 'sofia@user.com', 1);

  1. INSERTAR CREDENCIALES Y ROLES (UserCredentials)
-- Contraseñas: lautaropass, mariapass, sofiapass, hasheadas con bcrypt
-- Reemplaza los placeholders de HASH_... por los hashes generados por hash_generator.py

INSERT INTO user_credentials (id, user_id, password_hash, role) VALUES (
    1, 1, 'HASH_DE_LAUTAROPASS', 'admin'
);
INSERT INTO user_credentials (id, user_id, password_hash, role) VALUES (
    2, 2, 'HASH_DE_MARIAPASS', 'moderator'
);
INSERT INTO user_credentials (id, user_id, password_hash, role) VALUES (
    3, 3, 'HASH_DE_SOFIAPASS', 'user'
);

  1. INSERTAR POSTS DE PRUEBA
INSERT INTO post (id, title, content, date_time, user_id, is_active, categoria_id) VALUES (
    1, 'Primer Post Admin', 'Contenido del primer post hecho por el administrador.', NOW(), 1, 1, 1
);
INSERT INTO post (id, title, content, date_time, user_id, is_active, categoria_id) VALUES (
    2, 'Noticia Importante', 'Este post es de un usuario normal.', NOW(), 3, 1, 3
);

  1. INSERTAR COMENTARIOS DE PRUEBA
INSERT INTO comment (id, content, date_time, user_id, post_id, is_active) VALUES (
    1, '¡Excelente artículo!', NOW(), 2, 1, 1
);
INSERT INTO comment (id, content, date_time, user_id, post_id, is_active) VALUES (
    2, 'Buen resumen de la noticia.', NOW(), 1, 2, 1
);

4. Archivo de Prueba (Postman Collection)

api_requests.http

HTTP

### =================================================================
### AUTENTICACIÓN
### =================================================================

# @name loginAdmin
POST [http://127.0.0.1:5000/login](http://127.0.0.1:5000/login)
Content-Type: application/json

{
    "email": "lautaro@admin.com",
    "password": "lautaropass"
}

### @name loginUser
POST [http://127.0.0.1:5000/login](http://127.0.0.1:5000/login)
Content-Type: application/json

{
    "email": "sofia@user.com",
    "password": "sofiapass"
}

### =================================================================
### POSTS (LECTURA PÚBLICA)
### =================================================================

# GET Posts activos
GET [http://127.0.0.1:5000/posts/active](http://127.0.0.1:5000/posts/active)

### GET Post por categoría (ID 1: Tecnología)
GET [http://127.0.0.1:5000/posts/category/1](http://127.0.0.1:5000/posts/category/1)

### GET Post por ID (asumiendo ID 1)
GET [http://127.0.0.1:5000/posts/1](http://127.0.0.1:5000/posts/1)

### GET Comentarios de un Post (asumiendo ID 1)
GET [http://127.0.0.1:5000/posts/1/comments/](http://127.0.0.1:5000/posts/1/comments/)

### =================================================================
### POSTS (CREACIÓN - REQUIERE AUTH)
### =================================================================

# @name createPost
POST [http://127.0.0.1:5000/posts/](http://127.0.0.1:5000/posts/)
Content-Type: application/json
Authorization: Bearer {{loginUser.response.body.access_token}}

{
    "title": "Nuevo Post del Usuario",
    "content": "Este es el contenido de prueba del post.",
    "categoria_id": 2
}

### =================================================================
### POSTS (UPDATE/DELETE - REQUIERE AUTOR/ADMIN)
### =================================================================

# @name updatePost
PUT [http://127.0.0.1:5000/posts/2](http://127.0.0.1:5000/posts/2)
Content-Type: application/json
Authorization: Bearer {{loginAdmin.response.body.access_token}}

{
    "title": "Post 2 Actualizado por Admin",
    "content": "El admin puede editar el post de un usuario."
}

### DELETE Post (Soft Delete)
# El usuario 3 (SofiaUser) elimina su propio post (asumiendo post ID 2)
DELETE [http://127.0.0.1:5000/posts/2](http://127.0.0.1:5000/posts/2)
Authorization: Bearer {{loginUser.response.body.access_token}}


### =================================================================
### USER MANAGEMENT (ADMIN ONLY)
### =================================================================

# @name listUsers
GET [http://127.0.0.1:5000/users/](http://127.0.0.1:5000/users/)
Authorization: Bearer {{loginAdmin.response.body.access_token}}

### PUT Change Role (Asumiendo user ID 3, rol 'user' a 'moderator')
PUT [http://127.0.0.1:5000/users/3/role](http://127.0.0.1:5000/users/3/role)
Content-Type: application/json
Authorization: Bearer {{loginAdmin.response.body.access_token}}

{
    "role": "moderator"
}

### =================================================================
### STATS (ADMIN/MODERATOR ONLY)
### =================================================================

# GET Stats (Admin obtiene todas las métricas)
GET [http://127.0.0.1:5000/stats/](http://127.0.0.1:5000/stats/)
Authorization: Bearer {{loginAdmin.response.body.access_token}}

### GET Stats (User obtiene error 403)
GET [http://127.0.0.1:5000/stats/](http://127.0.0.1:5000/stats/)
Authorization: Bearer {{loginUser.response.body.access_token}}

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages