crunk
11 months ago
12 changed files with 480 additions and 0 deletions
@ -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) |
@ -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) |
@ -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) |
@ -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") |
@ -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") |
@ -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") |
@ -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") |
@ -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") |
@ -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 %} |
@ -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 %} |
@ -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 %} |
@ -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 %} |
Loading…
Reference in new issue