| @ -0,0 +1,62 @@ | |||||
| from flask import Blueprint, render_template, redirect, url_for, request, flash | |||||
| from werkzeug.security import generate_password_hash, check_password_hash | |||||
| from flask_login import login_user, logout_user, login_required | |||||
| from .models import User | |||||
| from . import db | |||||
| bp = Blueprint('auth', __name__) | |||||
| @bp.route('/login') | |||||
| def login(): | |||||
| return render_template('login.html') | |||||
| @bp.route('/login', methods=['POST']) | |||||
| def login_post(): | |||||
| email = request.form.get('email') | |||||
| password = request.form.get('password') | |||||
| remember = True if request.form.get('remember') else False | |||||
| user = User.query.filter_by(email=email).first() | |||||
| # check if the user actually exists | |||||
| # take the user-supplied password, hash it, and compare it to the hashed password in the database | |||||
| if not user or not check_password_hash(user.password, password): | |||||
| flash('Por favor, comprueba los datos de registro y vuelve a intentarlo.') | |||||
| return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page | |||||
| # if the above check passes, then we know the user has the right credentials | |||||
| login_user(user, remember=remember) | |||||
| return redirect(url_for('reservas.misreservas')) | |||||
| @bp.route('/signup') | |||||
| def signup(): | |||||
| return render_template('signup.html') | |||||
| @bp.route('/signup', methods=['POST']) | |||||
| def signup_post(): | |||||
| email = request.form.get('email') | |||||
| name = request.form.get('name') | |||||
| password = request.form.get('password') | |||||
| user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database | |||||
| if user: # if a user is found, we want to redirect back to signup page so user can try again | |||||
| flash('La dirección de correo ya existe') | |||||
| return redirect(url_for('auth.signup')) | |||||
| # create a new user with the form data. Hash the password so the plaintext version isn't saved. | |||||
| new_user = User(email=email, name=name, password=generate_password_hash(password, method='pbkdf2:sha256')) | |||||
| # add the new user to the database | |||||
| db.session.add(new_user) | |||||
| db.session.commit() | |||||
| return redirect(url_for('auth.login')) | |||||
| @bp.route('/logout') | |||||
| @login_required | |||||
| def logout(): | |||||
| logout_user() | |||||
| return redirect(url_for('auth.index')) | |||||
| @ -0,0 +1,75 @@ | |||||
| <nav class="navbar is-dark" role="navigation" aria-label="main navigation"> | |||||
| <div class="navbar-brand"> | |||||
| <img src="./static/bruce.jpeg" class="image is-48x48"/> | |||||
| <a class="navbar-item" href="/">Letras de canciones</a> | |||||
| <div class="navbar-burger" role="button" data-target="navMenu"> | |||||
| <span></span> | |||||
| {% if current_user.is_authenticated %} | |||||
| <span></span> | |||||
| <span></span> | |||||
| {% else %} | |||||
| <span></span> | |||||
| <span></span> | |||||
| {% endif %} | |||||
| </div> | |||||
| </div> | |||||
| <div class="navbar-menu" id="navMenu"> | |||||
| <div class="navbar-end"> | |||||
| <a class="navbar-item" href="{{ url_for('paginas.index') }}" > | |||||
| Inicio | |||||
| </a> | |||||
| <div class="navbar-item"> | |||||
| <!-- <div class="buttons">--> | |||||
| {% if current_user.is_authenticated %} | |||||
| <div class="navbar-item has-dropdown is-hoverable"> | |||||
| <a class="navbar-link"> | |||||
| {{ current_user.name }} | |||||
| </a> | |||||
| <div class="navbar-dropdown"> | |||||
| <a href="{{ url_for('reservas.misreservas') }}" class="navbar-item">Mis reservas</a> | |||||
| <a href="{{ url_for('auth.logout') }}" class="navbar-item">Salir</a> | |||||
| </div> | |||||
| </div> | |||||
| {% else %} | |||||
| <a href="{{ url_for('auth.login') }}" class="button is-primary">Entrar</a> | |||||
| <a href="{{ url_for('auth.signup') }}" class="button is-light">Registrarse</a> | |||||
| {% endif %} | |||||
| <!--</div>--> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <script> | |||||
| document.addEventListener('DOMContentLoaded', function () { | |||||
| // Get all "navbar-burger" elements | |||||
| var $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); | |||||
| // Check if there are any navbar burgers | |||||
| if ($navbarBurgers.length > 0) { | |||||
| // Add a click event on each of them | |||||
| $navbarBurgers.forEach(function ($el) { | |||||
| $el.addEventListener('click', function () { | |||||
| // Get the target from the "data-target" attribute | |||||
| var target = $el.dataset.target; | |||||
| var $target = document.getElementById(target); | |||||
| // Toggle the class on both the "navbar-burger" and the "navbar-menu" | |||||
| $el.classList.toggle('is-active'); | |||||
| $target.classList.toggle('is-active'); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| }); | |||||
| </script> | |||||
| </nav> | |||||
| @ -0,0 +1,36 @@ | |||||
| {% extends "base.html" %} | |||||
| {% block content %} | |||||
| <div class="column is-4 is-offset-4"> | |||||
| <h3 class="title">Login</h3> | |||||
| <div class="box"> | |||||
| {% with messages = get_flashed_messages() %} | |||||
| {% if messages %} | |||||
| <div class="notification is-danger"> | |||||
| {{ messages[0] }} | |||||
| </div> | |||||
| {% endif %} | |||||
| {% endwith %} | |||||
| <form method="POST" action="/login"> | |||||
| <div class="field"> | |||||
| <div class="control"> | |||||
| <input class="input is-large" type="email" name="email" placeholder="Tu correo" autofocus=""> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="control"> | |||||
| <input class="input is-large" type="password" name="password" placeholder="Tu contraseña"> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label class="checkbox"> | |||||
| <input type="checkbox"> | |||||
| Recuerdame | |||||
| </label> | |||||
| </div> | |||||
| <button class="button is-block is-info is-large is-fullwidth">Entrar</button> | |||||
| </form> | |||||
| </div> | |||||
| </div> | |||||
| {% endblock %} | |||||
| @ -0,0 +1,56 @@ | |||||
| {% extends "base.html" %} | |||||
| {% block content %} | |||||
| <div class="column is-4 is-offset-4"> | |||||
| <h3 class="title">Nuevo usuario</h3> | |||||
| <div class="box"> | |||||
| {% with messages = get_flashed_messages() %} | |||||
| {% if messages %} | |||||
| <div class="notification is-danger"> | |||||
| {{ messages[0] }}. Go to <a href="{{ url_for('auth.login') }}">login page</a>. | |||||
| </div> | |||||
| {% endif %} | |||||
| {% endwith %} | |||||
| <form method="POST" action="/signup"> | |||||
| <div class="field"> | |||||
| <div class="control"> | |||||
| <input class="input is-large" type="email" name="email" placeholder="Email" autofocus=""> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="control"> | |||||
| <input class="input is-large" type="text" name="name" placeholder="Nombre" autofocus=""> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="control"> | |||||
| <input class="input is-large" type="password" name="password" placeholder="Password"> | |||||
| </div> | |||||
| </div> | |||||
| <button class="button is-block is-info is-large is-fullwidth">Registrarse</button> | |||||
| </form> | |||||
| </div> | |||||
| <div class="box"> | |||||
| <article class="media"> | |||||
| <div class="media-content"> | |||||
| <div class="content"> | |||||
| <h3> | |||||
| Información importante. | |||||
| </h3> | |||||
| <p> | |||||
| El correo se usará exclusivamente para informarte de que has hecho una reserva. | |||||
| </p> | |||||
| <p> | |||||
| El nombre aparecerá en el listado de reservas. | |||||
| </p> | |||||
| </div> | |||||
| </div> | |||||
| </article> | |||||
| </div> | |||||
| </div> | |||||
| {% endblock %} | |||||
| @ -1,11 +1,14 @@ | |||||
| blinker==1.8.2 | blinker==1.8.2 | ||||
| click==8.1.7 | click==8.1.7 | ||||
| Flask==3.0.3 | Flask==3.0.3 | ||||
| Flask-Login==0.6.3 | |||||
| Flask-SQLAlchemy==3.1.1 | Flask-SQLAlchemy==3.1.1 | ||||
| greenlet==3.0.3 | |||||
| gunicorn==22.0.0 | |||||
| itsdangerous==2.2.0 | itsdangerous==2.2.0 | ||||
| Jinja2==3.1.4 | Jinja2==3.1.4 | ||||
| MarkupSafe==2.1.5 | MarkupSafe==2.1.5 | ||||
| packaging==24.1 | |||||
| SQLAlchemy==2.0.31 | SQLAlchemy==2.0.31 | ||||
| typing_extensions==4.12.2 | typing_extensions==4.12.2 | ||||
| Werkzeug==3.0.3 | Werkzeug==3.0.3 | ||||
| gunicorn==22.0.0 | |||||