user login scaffolding

This commit is contained in:
crunk 2023-12-03 11:33:07 +01:00
parent 4a2e6f76ca
commit c77661e985
12 changed files with 480 additions and 0 deletions

View File

@ -0,0 +1,58 @@
from uuid import uuid1
from datetime import datetime
from sqlalchemy.exc import (
DataError,
DatabaseError,
InterfaceError,
InvalidRequestError,
)
from flask import render_template
from flask_mail import Message
from usermodel import User
from forms.forgotpasswordform import ForgotPasswordForm
from app import db
def ForgotPassword(mail):
forgotpasswordform = ForgotPasswordForm()
if forgotpasswordform.validate_on_submit():
user = User.query.filter_by(
email=forgotpasswordform.email.data
).first()
if user is not None:
resethash = AddResetPasswordHash(user, forgotpasswordform)
ResetPassWordMessage(user, resethash, mail)
forgotpasswordform.email.errors.append(
f"""If {forgotpasswordform.email.data} exists, an email is send with
a password reset link. (If your inbox doesn't
contain any new mail, please check your spam folder.)"""
)
return render_template(
"forgotpassword.html", forgotpasswordform=forgotpasswordform
)
def AddResetPasswordHash(user, forgotpasswordform):
resethash = uuid1().hex
try:
user.resettime = datetime.now()
user.resethash = resethash
db.session.commit()
except (InvalidRequestError, DataError, InterfaceError, DatabaseError):
forgotpasswordform.email.errors.append("Something went wrong!")
db.session.rollback()
return resethash
def ResetPassWordMessage(user, resethash, mail):
msg = Message(
"Forgotten Password ",
sender=("mailer", "test@this.com"),
recipients=[user.email],
)
msg.html = f"""{user.username} has requested a password reset for
libary website.<br><hr>
<a href='http://localhost:5000/resetpassword/{resethash}'>Click here to
reset your password.</a>"""
mail.send(msg)

View File

@ -0,0 +1,36 @@
from flask import (
render_template,
redirect,
request,
flash,
url_for,
abort,
)
from usermodel import User
from forms.loginform import LoginForm
from flask_login import login_user
from flask_bcrypt import check_password_hash
def LoginUser():
loginform = LoginForm()
if loginform.validate_on_submit():
try:
user = User.query.filter_by(email=loginform.email.data).first()
if user is None:
loginform.password.errors.append("Invalid email or password!")
return render_template("login.html", loginform=loginform)
if check_password_hash(user.password, loginform.password.data):
login_user(user)
flash("Logged in successfully.", "success")
next = request.args.get("next")
if next is not None and not is_safe_url(next): # noqa: F821
return abort(400)
return redirect(next or url_for("index"))
else:
flash("Invalid email or password!", "danger")
loginform.password.errors.append("Invalid email or password!")
return render_template("login.html", loginform=loginform)
except Exception as e:
flash(e, "danger")
return render_template("login.html", loginform=loginform)

View File

@ -0,0 +1,70 @@
from flask import (
render_template,
redirect,
flash,
url_for,
)
from sqlalchemy.exc import (
IntegrityError,
DataError,
DatabaseError,
InterfaceError,
InvalidRequestError,
)
from werkzeug.routing import BuildError
from usermodel import User
from forms.registerform import RegisterForm
from flask_login import login_user
from flask_bcrypt import generate_password_hash
from app import db
def RegisterUser():
registerform = RegisterForm()
if registerform.validate_on_submit():
try:
username = registerform.username.data
email = registerform.email.data
password = registerform.confirmpassword.data
newuser = User(
username=username,
email=email,
password=generate_password_hash(password),
)
db.session.add(newuser)
db.session.commit()
flash("Account Succesfully created", "success")
login_user(newuser)
return redirect(url_for("index"))
except InvalidRequestError:
db.session.rollback()
registerform.email.errors.append("Something went wrong!")
flash("Something went wrong!", "danger")
except IntegrityError:
db.session.rollback()
registerform.email.errors.append("User already exists!")
flash("User already exists!", "warning")
except DataError:
db.session.rollback()
registerform.email.errors.append("Invalid Entry")
flash("Invalid Entry", "warning")
except InterfaceError:
db.session.rollback()
registerform.email.errors.append(
"Error connecting to the database"
)
flash("Error connecting to the database", "danger")
except DatabaseError:
db.session.rollback()
registerform.email.errors.append(
"Error connecting to the database"
)
flash("Error connecting to the database", "danger")
except BuildError:
db.session.rollback()
registerform.email.errors.append("Unknown error occured!")
flash("An error occured !", "danger")
return render_template("register.html", registerform=registerform)

View File

@ -0,0 +1,81 @@
from datetime import datetime
from flask import (
render_template,
redirect,
flash,
url_for,
)
from sqlalchemy.exc import (
IntegrityError,
DataError,
DatabaseError,
InterfaceError,
InvalidRequestError,
)
from werkzeug.routing import BuildError
from usermodel import User
from forms.resetpasswordform import ResetPasswordForm
from flask_login import login_user
from flask_bcrypt import generate_password_hash
from app import db
def ResetPassword(path):
linkvalid = False
user = User.query.filter_by(resethash=path).first()
if user is None:
return redirect(url_for("index"))
timepassed = datetime.now() - user.resettime
if timepassed.days < 1:
linkvalid = True
resetpasswordform = ResetPasswordForm()
if resetpasswordform.validate_on_submit():
return ResetUserPasswordInDB(user, resetpasswordform)
return render_template(
"resetpassword.html",
resetpasswordform=resetpasswordform,
path=path,
linkvalid=linkvalid,
)
def ResetUserPasswordInDB(user, resetpasswordform):
try:
newpassword = resetpasswordform.confirmpassword.data
user.password = generate_password_hash(newpassword)
user.resethash = None
user.resettime = None
db.session.commit()
flash("Password Succesfully updated", "success")
login_user(user)
return redirect(url_for("index"))
except InvalidRequestError:
db.session.rollback()
resetpasswordform.email.errors.append("Something went wrong!")
flash("Something went wrong!", "danger")
except IntegrityError:
db.session.rollback()
resetpasswordform.email.errors.append("User already exists!")
flash("User already exists!", "warning")
except DataError:
db.session.rollback()
resetpasswordform.email.errors.append("Invalid Entry")
flash("Invalid Entry", "warning")
except InterfaceError:
db.session.rollback()
resetpasswordform.email.errors.append(
"Error connecting to the database"
)
flash("Error connecting to the database", "danger")
except DatabaseError:
db.session.rollback()
resetpasswordform.email.errors.append(
"Error connecting to the database"
)
flash("Error connecting to the database", "danger")
except BuildError:
db.session.rollback()
resetpasswordform.email.errors.append("Unknown error occured!")
flash("An error occured !", "danger")

View File

@ -0,0 +1,19 @@
"""Forgotten password form to help user."""
from wtforms import (
StringField,
SubmitField,
)
from wtforms import validators
from wtforms.validators import Length, Email
from flask_wtf import FlaskForm
class ForgotPasswordForm(FlaskForm):
"""Forgotten password csv-library form"""
email = StringField(
"Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)],
)
submit = SubmitField("Send email")

View File

@ -0,0 +1,23 @@
"""Login form to validate user."""
from wtforms import (
StringField,
SubmitField,
PasswordField,
)
from wtforms import validators
from wtforms.validators import Length, Email
from flask_wtf import FlaskForm
class LoginForm(FlaskForm):
"""Login csv-library form"""
email = StringField(
"Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)],
)
password = PasswordField(
"Password:", validators=[validators.InputRequired()]
)
submit = SubmitField("Sign In")

View File

@ -0,0 +1,43 @@
"""Register form to make a new user."""
from wtforms import (
StringField,
SubmitField,
PasswordField,
)
from wtforms import validators
from wtforms.validators import Length, Email, EqualTo, ValidationError
from flask_wtf import FlaskForm
class RegisterForm(FlaskForm):
"""Register for csv-library form"""
username = StringField(
"Username:",
validators=[validators.InputRequired(), Length(3, 150)],
)
email = StringField(
"Email address:",
validators=[
validators.InputRequired(),
Email(),
Length(6, 64),
]
)
password = PasswordField(
"New password:",
validators=[validators.InputRequired(), Length(12, 72)],
)
confirmpassword = PasswordField(
"Confirm your password:",
validators=[
validators.InputRequired(),
Length(12, 72),
EqualTo("password", message="Passwords must match !"),
],
)
submit = SubmitField("Register to the library")

View File

@ -0,0 +1,27 @@
"""Reset Password Form form to reset a users PasswordField."""
from wtforms import (
SubmitField,
PasswordField,
)
from wtforms import validators
from wtforms.validators import Length, EqualTo
from flask_wtf import FlaskForm
class ResetPasswordForm(FlaskForm):
"""ResetPassword for csv-library form"""
password = PasswordField(
"New password:",
validators=[validators.InputRequired(), Length(12, 72)],
)
confirmpassword = PasswordField(
"Confirm your password:",
validators=[
validators.InputRequired(),
Length(12, 72),
EqualTo("password", message="Passwords must match !"),
],
)
submit = SubmitField("Reset your password")

View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block main %}
<div id="mainworkflow">
<div class="workflow">
<h2>Forgot your password?</h2>
<p>
Enter the email address that was used to register with the library.
</p>
<form class="form" action="{{ url_for('forgotpassword') }}" method="post">
{{ forgotpasswordform.csrf_token }}
<fieldset class="required">
{{ forgotpasswordform.email.label }}
{{ forgotpasswordform.email }}
{% for message in forgotpasswordform.email.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="button required error">
{{ forgotpasswordform.submit }}
<div class="overview">
<a href="/">
<input type="button" name="button" value="Back to main page"></input>
</a>
</div>
</fieldset>
</form>
</div>
</div
{% endblock main %}

View File

@ -0,0 +1,26 @@
{% extends "base.html" %}
{% block main %}
<div id="login">
<form class="form" action="{{ url_for('login') }}" method="post">
{{ loginform.csrf_token }}
<fieldset class="required">
{{ loginform.email.label }}
{{ loginform.email }}
{% for message in loginform.email.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="required">
{{ loginform.password.label }}
{{ loginform.password }}
{% for message in loginform.password.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="button required">
{{ loginform.submit }}
<a href="/forgotpassword">Forgot Password?</a>
</fieldset>
</form>
</div>
{% endblock main %}

View File

@ -0,0 +1,39 @@
{% extends "base.html" %}
{% block main %}
<div id="login">
<form class="form" action="{{ url_for('register') }}" method="post">
{{ registerform.csrf_token }}
<fieldset class="required">
{{ registerform.username.label }}
{{ registerform.username }}
{% for message in registerform.username.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="required">
{{ registerform.email.label }}
{{ registerform.email }}
{% for message in registerform.email.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="required">
{{ registerform.password.label }}
{{ registerform.password }}
{% for message in registerform.password.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="required">
{{ registerform.confirmpassword.label }}
{{ registerform.confirmpassword }}
{% for message in registerform.confirmpassword.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="button required">
{{ registerform.submit }}
</fieldset>
</form>
</div>
{% endblock main %}

View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block main %}
<div id="login">
{% if linkvalid%}
<form class="form" action="{{ url_for('resetpassword', path=path) }}" method="post">
{{ resetpasswordform.csrf_token }}
<fieldset class="required">
{{ resetpasswordform.password.label }}
{{ resetpasswordform.password }}
{% for message in resetpasswordform.password.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="required">
{{ resetpasswordform.confirmpassword.label }}
{{ resetpasswordform.confirmpassword }}
{% for message in resetpasswordform.confirmpassword.errors %}
<div class="error">{{ message }}</div>
{% endfor %}
</fieldset>
<fieldset class="button required">
{{ resetpasswordform.submit }}
</fieldset>
</form>
{% else %}
<h3>Password reset link no longer valid.</h3>
{% endif %}
</div>
{% endblock main %}