diff --git a/app/__init__.py b/app/__init__.py index 5299b5b..90d7fb3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,6 +3,8 @@ from flasgger import Swagger from app.database import db from app.models.user import User from app.routes.user_routes import user_bp +from app.routes.login_form import login_bp +from app.routes.dashboard import dashboard_bp from app.routes.invoice_routes import invoice_bp from werkzeug.security import generate_password_hash @@ -54,5 +56,7 @@ def create_app(): # Registrar Blueprints app.register_blueprint(user_bp, url_prefix="/users") app.register_blueprint(invoice_bp, url_prefix="/invoices") + app.register_blueprint(login_bp, url_prefix="/login_bp") + app.register_blueprint(dashboard_bp, url_prefix="/dashboard") return app diff --git a/app/controllers/__init__.py b/app/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/controllers/auth_controller.py b/app/controllers/auth_controller.py new file mode 100644 index 0000000..85395b2 --- /dev/null +++ b/app/controllers/auth_controller.py @@ -0,0 +1,13 @@ +from app.auth import generate_token +from app.models.user import User +from werkzeug.security import check_password_hash +from flask import jsonify + +def authenticate_user(email, password): + user = User.query.filter_by(email=email).first() + + if not user or not check_password_hash(user.password, password): + return None, None + + token = generate_token(user) + return user, token diff --git a/app/routes/dashboard.py b/app/routes/dashboard.py new file mode 100644 index 0000000..3931a6b --- /dev/null +++ b/app/routes/dashboard.py @@ -0,0 +1,12 @@ +from flask import Blueprint, render_template, session, redirect, url_for, flash + +dashboard_bp = Blueprint("dashboard", __name__, template_folder="templates") + +@dashboard_bp.route("/") +def dashboard(): + """Protege a rota do dashboard""" + if "user_id" not in session: + flash("Faça login para acessar o dashboard.", "warning") + return redirect(url_for("login_form.login")) + + return render_template("dashboard.html", user_email=session.get("user_email")) diff --git a/app/routes/login_form.py b/app/routes/login_form.py new file mode 100644 index 0000000..ed265e9 --- /dev/null +++ b/app/routes/login_form.py @@ -0,0 +1,30 @@ +from flask import Blueprint, render_template, request, redirect, url_for, flash, session +from app.controllers.auth_controller import authenticate_user + +login_bp = Blueprint("login_form", __name__, template_folder="templates") + +@login_bp.route("/", methods=["GET", "POST"]) +def login(): + """Rota de login""" + if request.method == "POST": + email = request.form.get("email") + password = request.form.get("password") + + user, token = authenticate_user(email, password) + + if user: + session["user_id"] = user.id + session["user_email"] = user.email + flash("Login bem-sucedido!", "success") + return redirect(url_for("dashboard.dashboard")) + + flash("Credenciais inválidas!", "danger") + + return render_template("login.html") + +@login_bp.route("/logout") +def logout(): + """Rota de logout""" + session.clear() + flash("Você saiu da conta.", "info") + return redirect(url_for("login_form.login")) diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html new file mode 100644 index 0000000..a4f6e3c --- /dev/null +++ b/app/templates/dashboard.html @@ -0,0 +1,13 @@ + + + + + + Dashboard + + +

Bem-vindo ao Dashboard!

+

Usuário logado: {{ user_email }}

+ Sair + + diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..6384905 --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,32 @@ + + + + + + Login + + + +
+

Login

+ + {% with messages = get_flashed_messages(with_categories=True) %} + {% if messages %} + {% for category, message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} + {% endwith %} + +
+ + + + + + + +
+
+ + diff --git a/requirements.txt b/requirements.txt index 9e4be8f..2ea97f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,16 @@ attrs==25.1.0 blinker==1.9.0 click==8.1.8 +exceptiongroup==1.2.2 factory_boy==3.3.3 Faker==36.2.2 flasgger==0.9.7.1 Flask==3.1.0 +Flask-JWT-Extended==4.7.1 Flask-SQLAlchemy==3.1.1 Flask-Testing==0.8.1 greenlet==3.1.1 +importlib_metadata==8.6.1 iniconfig==2.0.0 itsdangerous==2.2.0 Jinja2==3.1.6 @@ -17,12 +20,15 @@ MarkupSafe==3.0.2 mistune==3.1.2 packaging==24.2 pluggy==1.5.0 +PyJWT==2.10.1 pytest==8.3.5 PyYAML==6.0.2 referencing==0.36.2 rpds-py==0.23.1 six==1.17.0 SQLAlchemy==2.0.38 +tomli==2.2.1 typing_extensions==4.12.2 tzdata==2025.1 Werkzeug==3.1.3 +zipp==3.21.0