feat(users): adds login functionality
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
from werkzeug.datastructures import ImmutableMultiDict
|
from werkzeug.datastructures import ImmutableMultiDict
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
from flask import flash, session
|
from flask import flash, session
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
@@ -47,4 +47,21 @@ class UserService:
|
|||||||
raise UserRegisterErrors("Something went wrong")
|
raise UserRegisterErrors("Something went wrong")
|
||||||
except UserRegisterErrors as e:
|
except UserRegisterErrors as e:
|
||||||
flash(FlashMessage(e.message, AlertType.DANGER.value ))
|
flash(FlashMessage(e.message, AlertType.DANGER.value ))
|
||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def login(form: ImmutableMultiDict):
|
||||||
|
try:
|
||||||
|
email = UserValidators.is_valid_email(form.get("email"))
|
||||||
|
password = UserValidators.is_valid_password(form.get("password"))
|
||||||
|
user_row = db.session.execute(db.select(User).filter_by(email=email)).one_or_none()
|
||||||
|
if user_row is not None:
|
||||||
|
if check_password_hash(user_row[0].password, password):
|
||||||
|
session["id"] = user_row[0].id
|
||||||
|
return True
|
||||||
|
flash(FlashMessage("Invalid email or password", AlertType.DANGER.value ))
|
||||||
|
return False
|
||||||
|
except UserRegisterErrors as e:
|
||||||
|
flash(FlashMessage(e.message, AlertType.DANGER.value ))
|
||||||
|
|
||||||
|
|
||||||
9
app/static/css/login.css
Normal file
9
app/static/css/login.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.login {
|
||||||
|
max-width: 480px;
|
||||||
|
}
|
||||||
|
.register__form-button {
|
||||||
|
width: 100%;
|
||||||
|
@media(min-width: 576px) {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,51 @@
|
|||||||
{% extends "layout/layout.html" %}
|
{% extends "layout/layout.html" %}
|
||||||
|
{% from "layout/inner_header.html" import inner_header%}
|
||||||
|
{% from "forms/validation-block.html" import form_field_validation %}
|
||||||
|
{% from "forms/submit-btn.html" import form_submit_button %}
|
||||||
{% block title %} Login {% endblock %}
|
{% block title %} Login {% endblock %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Login!</h1>
|
<div class="login container h-100">
|
||||||
{% endblock %}
|
<div class="row">
|
||||||
|
<div class="col-12 my-3">
|
||||||
|
{{ inner_header("Login") }}
|
||||||
|
</div>
|
||||||
|
<form class="col-12 needs-validation h-100" method="post" novalidate>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Email</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
pattern="[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$"
|
||||||
|
placeholder="Enter your email address"
|
||||||
|
required
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
{{ form_field_validation(FORM_ERRORS['REQUIRED'] + " " + FORM_ERRORS['VALID_EMAIL']) }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Password</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
id="password"
|
||||||
|
maxlength="255"
|
||||||
|
minlength="6"
|
||||||
|
name="password"
|
||||||
|
placeholder="Enter password"
|
||||||
|
required
|
||||||
|
type="password"
|
||||||
|
>
|
||||||
|
{{ form_field_validation(FORM_ERRORS['REQUIRED'] + " " + FORM_ERRORS['PASSWORD_LENGTH']) }}
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-auto">
|
||||||
|
{{ form_submit_button("Login") }}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="{{ url_for('static', filename='js/validate-form.js') }}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@@ -2,13 +2,19 @@ from flask import redirect, request, render_template, session
|
|||||||
from app.services.user_service import UserService
|
from app.services.user_service import UserService
|
||||||
from app.users import bp
|
from app.users import bp
|
||||||
from app.utils.form_errors_dict import FORM_ERRORS
|
from app.utils.form_errors_dict import FORM_ERRORS
|
||||||
|
from app.utils.helpers import login_required
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route('/')
|
||||||
|
@login_required
|
||||||
def index():
|
def index():
|
||||||
return render_template("users/index.html")
|
return render_template("users/index.html")
|
||||||
|
|
||||||
@bp.route('/login')
|
@bp.route('/login', methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
return render_template("users/login.html")
|
if request.method == 'POST':
|
||||||
|
if UserService.login(request.form):
|
||||||
|
return redirect("/")
|
||||||
|
return render_template("users/login.html", FORM_ERRORS=FORM_ERRORS)
|
||||||
|
|
||||||
@bp.route('/logout')
|
@bp.route('/logout')
|
||||||
def logout():
|
def logout():
|
||||||
|
|||||||
Reference in New Issue
Block a user