Skip to content

Commit 4db6777

Browse files
committed
230725e
1 parent 6afbf99 commit 4db6777

File tree

9 files changed

+73
-36
lines changed

9 files changed

+73
-36
lines changed

apiflaskdemo/__init__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
from apiflask import APIFlask
22
from apiflaskdemo.project.models import db, Alumno, User
3-
from apiflaskdemo.project.blueprints import abc_alumnos
3+
from apiflaskdemo.project.alumno.blueprints import abc_alumnos
44
from apiflaskdemo.project.auth.blueprints import auth_bp
5-
from sqlalchemy import inspect
65
from data.alumnos import data_alumnos as alumnos
76

87
def create_app():
98
'''Función principal de la aplicación'''
109
# Crear el objeto app
1110
app = APIFlask(__name__)
1211

12+
1313
# Obtener la configuración de la aplicación a partir de settings.py
1414
app.config.from_pyfile("settings.py")
1515

@@ -37,7 +37,7 @@ def create_app():
3737
db.session.commit()
3838

3939
# Registra los blueprints con los endpoints
40-
app.register_blueprint(abc_alumnos, url_prefix='/api')
40+
app.register_blueprint(abc_alumnos, url_prefix='/api/alumno/')
4141
app.register_blueprint(auth_bp, url_prefix='/auth')
4242

4343
#Regresa la aplicación

apiflaskdemo/project/alumno/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,60 @@
1+
"""Módulo de gestión de alumnos"""
2+
3+
14
from apiflask import APIBlueprint, abort
25
from apiflaskdemo.project.auth import login_required
36
from apiflaskdemo.project.models import db, Alumno
47
from apiflaskdemo.project.schemas import AlumnoSchema, AlumnoInSchema
5-
from marshmallow.exceptions import ValidationError
68

7-
abc_alumnos = APIBlueprint('abc_alumno', __name__)
9+
abc_alumnos = APIBlueprint('Gestión de alumnos', __name__)
10+
811

9-
@abc_alumnos.get("/alumnos/")
12+
@abc_alumnos.get("/alumnos")
1013
@abc_alumnos.output(AlumnoSchema(many=True))
11-
def vuelca_base():
14+
def vuelca_base() -> list[Alumno]:
15+
"""Devuelve todos los alumnos"""
1216
return Alumno.query.all()
1317

14-
@abc_alumnos.get("/alumno/<int:cuenta>")
18+
19+
@abc_alumnos.get("/<int:cuenta>")
1520
@abc_alumnos.output(AlumnoSchema)
16-
def despliega_alumno(cuenta):
21+
def despliega_alumno(cuenta: int) -> Alumno:
22+
"""Devuelve un alumno al ingresar su cuenta"""
1723
return Alumno.query.get_or_404(cuenta)
1824

19-
@abc_alumnos.delete("/alumno/<int:cuenta>")
20-
@abc_alumnos.output(AlumnoSchema)
25+
26+
@abc_alumnos.delete("/<int:cuenta>")
27+
@abc_alumnos.output({}, 200)
2128
@login_required
22-
def elimina_alumno(cuenta):
29+
def elimina_alumno(cuenta: int) -> None:
2330
alumno = Alumno.query.get_or_404(cuenta)
2431
db.session.delete(alumno)
2532
db.session.commit()
26-
return alumno
27-
28-
@abc_alumnos.post("/alumno/<int:cuenta>")
33+
return None
34+
35+
36+
@abc_alumnos.post("/<int:cuenta>")
2937
@abc_alumnos.output(AlumnoSchema, status_code=201)
3038
@abc_alumnos.input(AlumnoInSchema)
31-
def crea_alumno(cuenta, data):
39+
def crea_alumno(cuenta: int, data: dict) -> Alumno:
3240
if Alumno.query.filter_by(cuenta=cuenta).first():
3341
abort(409)
34-
else:
42+
else:
3543
data["cuenta"] = cuenta
3644
alumno = Alumno(**AlumnoSchema().load(data))
3745
db.session.add(alumno)
3846
db.session.commit()
3947
return alumno, 201
4048

41-
@abc_alumnos.put("/alumno/<int:cuenta>")
49+
50+
@abc_alumnos.put("/<int:cuenta>")
4251
@abc_alumnos.output(AlumnoSchema)
4352
@abc_alumnos.input(AlumnoInSchema)
44-
def sustituye_alumno(cuenta, data):
53+
def sustituye_alumno(cuenta: int, data: dict) -> Alumno:
4554
alumno = Alumno.query.get_or_404(cuenta)
4655
db.session.delete(alumno)
4756
data["cuenta"] = cuenta
4857
nuevo_alumno = Alumno(**data)
4958
db.session.add(nuevo_alumno)
5059
db.session.commit()
51-
return nuevo_alumno
60+
return nuevo_alumno

apiflaskdemo/project/auth/__init__.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from functools import wraps
2-
from flask import g, abort
2+
from flask import g, abort
3+
34

45
def login_required(view):
56
@wraps(view)
67
def wrapped_view(*args, **kwargs):
78
if g.user is None:
89
return abort(403)
9-
return view(*args,**kwargs)
10-
return wrapped_view
10+
return view(*args, **kwargs)
11+
return wrapped_view

apiflaskdemo/project/auth/blueprints.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1+
"""Blueprints for the auth module."""
2+
13
from apiflaskdemo.project.models import User
24
from apiflask import APIBlueprint, abort
3-
from apiflask.fields import String
45
from apiflaskdemo.project.auth.schemas import LoginSchema
56
from flask import session, g
67

78
auth_bp = APIBlueprint("auth_bp", __name__)
89

10+
911
@auth_bp.before_app_request
1012
def user_checkout():
1113
user_id = session.get("user_id")
1214
if user_id is None:
13-
g.user =None
15+
g.user = None
1416
else:
1517
g.user = User.query.filter_by(id=user_id).first()
1618

19+
1720
@auth_bp.post("/login")
1821
@auth_bp.input(LoginSchema)
1922
def login(data):
@@ -25,7 +28,8 @@ def login(data):
2528
else:
2629
abort(403)
2730

31+
2832
@auth_bp.get("/logout")
2933
def logout():
3034
session.clear()
31-
return {"msg": "logged out"}
35+
return {"msg": "logged out"}

apiflaskdemo/project/auth/schemas.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
"""Schemas for the auth module."""
2+
13
from apiflask import Schema
24
from apiflask.fields import String
35

6+
47
class LoginSchema(Schema):
58
username = String(required=True)
69
password = String(required=True)
7-

apiflaskdemo/project/models.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
"""Módulo de modelos de la aplicación"""
2+
13
from flask_sqlalchemy import SQLAlchemy
24
from flask_login.mixins import UserMixin
35

6+
# Instancia de SQLAlchemy
47
db = SQLAlchemy()
58

9+
610
class Alumno(UserMixin, db.Model):
11+
"""Modelo de alumno"""
712
__tablename__ = 'alumnos'
813
cuenta = db.Column(db.Integer, primary_key=True)
914
nombre = db.Column(db.String(50))
@@ -14,11 +19,13 @@ class Alumno(UserMixin, db.Model):
1419
promedio = db.Column(db.Float)
1520
al_corriente = db.Column(db.Boolean)
1621

22+
1723
class User(UserMixin, db.Model):
24+
"""Modelo de usuario"""
1825
__tablename__ = "user"
1926
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
2027
email = db.Column(db.String(255), nullable=False, unique=True)
21-
username= db.Column(db.String(25), nullable=False, unique=True)
28+
username = db.Column(db.String(25), nullable=False, unique=True)
2229
password = db.Column(db.String(255))
2330
active = db.Column(db.Boolean())
2431
authenticated = db.Column(db.Boolean())

apiflaskdemo/project/schemas.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1+
"""Esquemas de validación de datos de entrada y salida"""
2+
13
from apiflask.validators import OneOf, Length, Range
24
from apiflask.fields import String, Integer, Float, Boolean
35
from apiflask import Schema
46

5-
carreras = ("Sistemas", "Derecho", "Actuaría", "Arquitectura", "Administración")
7+
# Lista de carreras válidas
8+
carreras = ("Sistemas",
9+
"Derecho",
10+
"Actuaría",
11+
"Arquitectura",
12+
"Administración")
13+
614

715
class AlumnoSchema(Schema):
16+
"""Esquema de salida de alumno"""
817
cuenta = Integer(required=True, validate=Range(min=1000000, max=9999999))
918
nombre = String(required=True, validate=Length(min=2, max=50))
1019
primer_apellido = String(required=True, validate=Length(min=2, max=50))
@@ -14,11 +23,13 @@ class AlumnoSchema(Schema):
1423
promedio = Float(required=True, validate=Range(min=1, max=10))
1524
al_corriente = Boolean(required=True)
1625

26+
1727
class AlumnoInSchema(Schema):
28+
"""Esquema de entrada de alumno"""
1829
nombre = String(required=True, validate=Length(min=2, max=50))
1930
primer_apellido = String(required=True, validate=Length(min=2, max=50))
2031
segundo_apellido = String(required=False, validate=Length(min=2, max=50))
2132
carrera = String(required=True, validate=OneOf(carreras))
2233
semestre = Integer(required=True, validate=Range(min=1, max=50))
2334
promedio = Float(required=True, validate=Range(min=0, max=10))
24-
al_corriente = Boolean(required=True)
35+
al_corriente = Boolean(required=True)

tests/test_endpoints.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Módulo que contiene los tests de los endpoints de la API"""
2+
13
import pytest
24
from app import create_app
35
from apiflaskdemo.project.models import db, Alumno
@@ -16,7 +18,7 @@ def client() -> Request:
1618

1719
def test_get_alumnos(client) -> None:
1820
"""Test que comprueba que se pueden obtener los alumnos"""
19-
r = client.get('/api/alumnos/')
21+
r = client.get('/api/alumno/alumnos')
2022
print("Validando que se puedan obtener los alumnos...")
2123
assert r.status_code == 200
2224
print("Se pueden obtener los alumnos.")
@@ -91,6 +93,7 @@ def test_post_cuenta_duplicada(client):
9193
print("Validando que se pueda crear un alumno...")
9294
assert r.status_code == 409
9395

96+
9497
def test_put_alumno(client) -> None:
9598
"""Test que comprueba que se puede actualizar un alumno"""
9699
alumno = {
@@ -119,6 +122,7 @@ def test_login_required(client) -> None:
119122
print("Validando que se necesite iniciar sesión para eliminar un alumno...")
120123
assert r.status_code == 403
121124
print("Se necesita iniciar sesión para eliminar un alumno.")
125+
122126

123127
def test_login(client) -> None:
124128
"""Test que comprueba que se puede iniciar sesión"""
@@ -144,12 +148,11 @@ def test_del_alumno(client) -> None:
144148
print("Se puede iniciar sesión.")
145149
r = client.delete(f'/api/alumno/{data_alumnos[0]["cuenta"]}')
146150
print("Validando que se pueda eliminar un alumno...")
147-
assert r.status_code == 200
151+
assert r.status_code == 204
148152
print("Se puede eliminar un alumno.")
149-
print("Validando que los datos del alumno eliminado sean correctos...")
150-
alumno_response = AlumnoSchema().dump(r.json)
151-
assert alumno_response == data_alumnos[0]
152-
print("Datos del alumno eliminado son correctos.")
153+
print("Validando que el alumno haya sido eliminado...")
154+
r = client.get(f'/api/alumno/{data_alumnos[0]["cuenta"]}')
155+
assert r.status_code == 404
153156

154157

155158
def test_logout(client) -> None:

0 commit comments

Comments
 (0)