Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ wtforms = "==3.1.2"
sqlalchemy = "*"
flask-migrate = "*"
flask-swagger = "*"
flask-sqlalchemy = "*"
email-validator = "*"
tomli = "*"
flask = "*"
flask-cors = "*"
flask-sqlalchemy = "*"
flask-jwt-extended = "*"
flask-bcrypt = "*"
email-validator = "*"
tomli = "*"

[requires]
python_version = "3.13"
Expand All @@ -37,3 +37,8 @@ downgrade="flask db downgrade"
insert-test-data="flask insert-test-data"
reset_db="bash ./docs/assets/reset_migrations.bash"
deploy="echo 'Please follow this 3 steps to deploy: https://github.com/4GeeksAcademy/flask-rest-hello/blob/master/README.md#deploy-your-website-to-heroku' "
[packages]
Flask = "*"
flask-cors = "*"
flask-jwt-extended = "*"
flask-bcrypt = "*"
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""empty message

Revision ID: ec3dc653e85e
Revision ID: 4245641cec31
Revises:
Create Date: 2025-07-23 19:05:41.212111
Create Date: 2025-07-28 17:31:28.677550

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'ec3dc653e85e'
revision = '4245641cec31'
down_revision = None
branch_labels = None
depends_on = None
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ sqlalchemy==1.3.23
urllib3==1.26.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'
werkzeug==1.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
wtforms==2.3.3
flask-jwt-extended==3.25.1
flask-bcrypt==0.7.1
3 changes: 2 additions & 1 deletion src/api/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import String, ForeignKey, Integer, Float, Boolean
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy import Enum
from typing import List
import enum

Expand Down Expand Up @@ -36,7 +37,7 @@ def serialize(self):
class Order(db.Model):
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
status: Mapped[Status] = mapped_column(default= Status.CART)
status: Mapped[Status] = mapped_column(Enum(Status), default=Status.CART, nullable=False)


user: Mapped ["User"] = relationship(
Expand Down
85 changes: 80 additions & 5 deletions src/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from api.utils import generate_sitemap, APIException
from flask_cors import CORS
from flask_jwt_extended import jwt_required, create_access_token, get_jwt_identity
from api.models import User, db
from api.models import User, Order, Status, db, OrderItem
from flask_bcrypt import Bcrypt

api = Blueprint('api', __name__)
Expand All @@ -22,13 +22,13 @@ def handle_private_hello():
if user:
response_body = {
"message": "Hola, soy una ruta privada",
"user": user.serialize()
"user": user.serialize()
}
return jsonify(response_body), 200
else:
return jsonify({"message": "Usuario no encontrado"}), 404


# Login y Registro
@api.route('/login', methods=['POST'])
def login():
data_request = request.get_json()
Expand Down Expand Up @@ -63,7 +63,7 @@ def register():
data_request = request.get_json()
email = data_request.get('email')
password = data_request.get('password')
name = data_request.get('username')
name = data_request.get('username')

if not email or not password:
return jsonify({"message": "Los campos email,password son obligatorios"}), 400
Expand All @@ -73,7 +73,7 @@ def register():
new_user = User(
email=email,
password=hashed_password,
name=name,
name=name,
is_active=True
)

Expand All @@ -84,3 +84,78 @@ def register():
except Exception as e:
db.session.rollback()
return jsonify({"error": "Error en el servidor"}), 500

# Productos

# Carrito
@api.route('/cart', methods=['GET'])
@jwt_required()
def get_cart():

user_id = get_jwt_identity()
order = Order.query.filter_by(user_id=user_id, status=Status.CART).first()

if not order:
return jsonify({"message": "Carrito vacío"}), 400

return jsonify({
"order_id": order.id,
"items": [item.serialize() for item in order.order_item]
}), 200

@api.route('/cart/add', methods=['POST'])
@jwt_required()
def add_to_cart():
user_id = get_jwt_identity()
data = request.get_json()
cant = data["cant"]
product_id = data["product_id"]
order = Order.query.filter_by(user_id=user_id, status=Status.CART).first()
if not order:
new_order = Order(user_id= user_id, status= Status.CART)
db.session.add(new_order)
db.session.commit()
new_item = OrderItem(order_id = new_order.id, product_id = product_id, cant = cant)
db.session.add(new_item)
db.session.commit()
return jsonify({
"order_id": new_order.id,
"item": new_item.serialize()
}), 200
else :
new_item = OrderItem(order_id = order.id, product_id = product_id, cant = cant)
db.session.add(new_item)
db.session.commit()
return jsonify({
"order_id": order.id,
"item": new_item.serialize()
}), 200

@api.route('/cart/delete/<int:id>', methods=['DELETE'])
@jwt_required()
def delete_to_cart(id):
user_id = get_jwt_identity()
order = Order.query.filter_by(user_id=user_id, status=Status.CART).first()
if not order:
return jsonify({"message": "Carrito no existe"}), 400

item = OrderItem.get(id)
db.session.delete(item)
db.session.commit()
return jsonify({"message": "Producto eliminado"}), 200


@api.route('/cart/checkout', methods=['POST'])
@jwt_required()
def checkout():
user_id = get_jwt_identity()
order = Order.query.filter_by(user_id=user_id, status=Status.CART).first()

if not order:
return jsonify({"message": "No hay carrito para finalizar"}), 400

order.status = Status.PAID
db.session.commit()

return jsonify({"message": "Compra finalizada", "order_id": order.id}), 200