halfway implementation of forgotten passwords
This commit is contained in:
parent
825013b3c2
commit
730a12accd
@ -2,9 +2,11 @@ alembic==1.7.5
|
|||||||
Babel==2.9.1
|
Babel==2.9.1
|
||||||
bcrypt==3.2.0
|
bcrypt==3.2.0
|
||||||
black==21.11b1
|
black==21.11b1
|
||||||
|
bleach==4.1.0
|
||||||
blinker==1.4
|
blinker==1.4
|
||||||
cffi==1.15.0
|
cffi==1.15.0
|
||||||
click==8.0.3
|
click==8.0.3
|
||||||
|
distribusi @ git+file:///home/shambler/Development/distribusiverse/distribusi@e291e7497e40211c2ebd54ca32a1f4bdaed71230
|
||||||
dnspython==2.1.0
|
dnspython==2.1.0
|
||||||
email-validator==1.1.3
|
email-validator==1.1.3
|
||||||
Flask==2.0.2
|
Flask==2.0.2
|
||||||
@ -15,6 +17,7 @@ Flask-Mail==0.9.1
|
|||||||
Flask-Migrate==3.1.0
|
Flask-Migrate==3.1.0
|
||||||
Flask-Principal==0.4.0
|
Flask-Principal==0.4.0
|
||||||
Flask-Security==3.0.0
|
Flask-Security==3.0.0
|
||||||
|
Flask-Security-Too==4.1.3
|
||||||
Flask-SQLAlchemy==2.5.1
|
Flask-SQLAlchemy==2.5.1
|
||||||
Flask-WTF==1.0.0
|
Flask-WTF==1.0.0
|
||||||
greenlet==1.1.2
|
greenlet==1.1.2
|
||||||
@ -24,11 +27,13 @@ Jinja2==3.0.3
|
|||||||
Mako==1.1.6
|
Mako==1.1.6
|
||||||
MarkupSafe==2.0.1
|
MarkupSafe==2.0.1
|
||||||
mypy-extensions==0.4.3
|
mypy-extensions==0.4.3
|
||||||
|
packaging==21.3
|
||||||
passlib==1.7.4
|
passlib==1.7.4
|
||||||
pathspec==0.9.0
|
pathspec==0.9.0
|
||||||
Pillow==8.3.2
|
Pillow==8.3.2
|
||||||
platformdirs==2.4.0
|
platformdirs==2.4.0
|
||||||
pycparser==2.21
|
pycparser==2.21
|
||||||
|
pyparsing==3.0.7
|
||||||
python-magic==0.4.24
|
python-magic==0.4.24
|
||||||
pytz==2021.3
|
pytz==2021.3
|
||||||
regex==2021.11.10
|
regex==2021.11.10
|
||||||
@ -36,7 +41,7 @@ six==1.16.0
|
|||||||
speaklater==1.3
|
speaklater==1.3
|
||||||
SQLAlchemy==1.4.27
|
SQLAlchemy==1.4.27
|
||||||
tomli==1.2.2
|
tomli==1.2.2
|
||||||
typing-extensions==4.0.1
|
typing_extensions==4.0.1
|
||||||
|
webencodings==0.5.1
|
||||||
Werkzeug==2.0.2
|
Werkzeug==2.0.2
|
||||||
WTForms==3.0.0
|
WTForms==3.0.0
|
||||||
-e git+https://git.vvvvvvaria.org/crunk/distribusi-verse.git@1a50898d216ae95c3eb9c144bb7ec678e638daa6#egg=distribusi
|
|
||||||
|
@ -22,6 +22,13 @@ def create_app():
|
|||||||
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
|
APP.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
|
||||||
APP.config["MAX_CONTENT_LENGTH"] = 150 * 1024 * 1024
|
APP.config["MAX_CONTENT_LENGTH"] = 150 * 1024 * 1024
|
||||||
|
|
||||||
|
APP.config["MAIL_SERVER"] = "0.0.0.0"
|
||||||
|
APP.config["MAIL_PORT"] = 1025
|
||||||
|
APP.config["MAIL_USE_SSL"] = False
|
||||||
|
APP.config["MAIL_USE_TLS"] = True
|
||||||
|
# APP.config['MAIL_USERNAME'] = 'username'
|
||||||
|
# APP.config['MAIL_PASSWORD'] = 'password'
|
||||||
|
|
||||||
login_manager.session_protection = "strong"
|
login_manager.session_protection = "strong"
|
||||||
login_manager.login_view = "index"
|
login_manager.login_view = "index"
|
||||||
login_manager.login_message_category = "info"
|
login_manager.login_message_category = "info"
|
||||||
|
19
verse/forms/forgotpasswordform.py
Normal file
19
verse/forms/forgotpasswordform.py
Normal 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 distribusiverse form class."""
|
||||||
|
|
||||||
|
email = StringField(
|
||||||
|
"Email address:",
|
||||||
|
validators=[validators.InputRequired(), Email(), Length(6, 64)],
|
||||||
|
)
|
||||||
|
submit = SubmitField("Send email")
|
@ -12,6 +12,7 @@ from flask_login import (
|
|||||||
login_required,
|
login_required,
|
||||||
current_user,
|
current_user,
|
||||||
)
|
)
|
||||||
|
from flask_mail import Mail
|
||||||
from flask_wtf.csrf import CSRFError
|
from flask_wtf.csrf import CSRFError
|
||||||
from app import create_app, login_manager
|
from app import create_app, login_manager
|
||||||
from usermodel import User
|
from usermodel import User
|
||||||
@ -31,11 +32,13 @@ from uploadpage import UploadPage
|
|||||||
from statuspengguna.helper import ResetUserState
|
from statuspengguna.helper import ResetUserState
|
||||||
from statuspengguna.loginuser import LoginUser
|
from statuspengguna.loginuser import LoginUser
|
||||||
from statuspengguna.registeruser import RegisterUser
|
from statuspengguna.registeruser import RegisterUser
|
||||||
|
from statuspengguna.forgotpassword import ForgotPassword
|
||||||
from distribusisinfo import DistribusisInfo
|
from distribusisinfo import DistribusisInfo
|
||||||
|
|
||||||
APP = create_app()
|
APP = create_app()
|
||||||
stash_page = Blueprint("stash_page", __name__, static_folder="stash")
|
stash_page = Blueprint("stash_page", __name__, static_folder="stash")
|
||||||
APP.register_blueprint(stash_page)
|
APP.register_blueprint(stash_page)
|
||||||
|
mail = Mail(APP)
|
||||||
|
|
||||||
|
|
||||||
@APP.before_request
|
@APP.before_request
|
||||||
@ -129,14 +132,17 @@ def logout():
|
|||||||
|
|
||||||
@APP.route("/login", methods=["GET", "POST"])
|
@APP.route("/login", methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
result = LoginUser()
|
return LoginUser()
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@APP.route("/register", methods=["GET", "POST"])
|
@APP.route("/register", methods=["GET", "POST"])
|
||||||
def register():
|
def register():
|
||||||
result = RegisterUser()
|
return RegisterUser()
|
||||||
return result
|
|
||||||
|
|
||||||
|
@APP.route("/forgotpassword", methods=["GET", "POST"])
|
||||||
|
def forgotpassword():
|
||||||
|
return ForgotPassword(mail)
|
||||||
|
|
||||||
|
|
||||||
@APP.errorhandler(CSRFError)
|
@APP.errorhandler(CSRFError)
|
||||||
|
34
verse/statuspengguna/forgotpassword.py
Normal file
34
verse/statuspengguna/forgotpassword.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from flask import render_template
|
||||||
|
from usermodel import User
|
||||||
|
from forms.forgotpasswordform import ForgotPasswordForm
|
||||||
|
from flask_mail import Message
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
ResetPassWordMessage(user, 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 ResetPassWordMessage(user, mail):
|
||||||
|
msg = Message(
|
||||||
|
"Distribusiverse Forgotten Password ",
|
||||||
|
sender=("Distribusiverse mailer", "test@this.com"),
|
||||||
|
recipients=[user.email],
|
||||||
|
)
|
||||||
|
msg.html = f"""You have requested a password reset for Distribusiverse.<br>
|
||||||
|
<a href='http://localhost:5000/resetpassword/{user.email}'>Click here to
|
||||||
|
reset your password and make a new one.</a>"""
|
||||||
|
mail.send(msg)
|
29
verse/templates/forgotpassword.html
Normal file
29
verse/templates/forgotpassword.html
Normal 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 Distribusiverse.
|
||||||
|
</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 %}
|
@ -12,6 +12,8 @@ class User(UserMixin, db.Model):
|
|||||||
email = db.Column(db.String(150), unique=True, nullable=False)
|
email = db.Column(db.String(150), unique=True, nullable=False)
|
||||||
password = db.Column(db.String(300), nullable=False, unique=False)
|
password = db.Column(db.String(300), nullable=False, unique=False)
|
||||||
currentdistribusi = db.Column(db.String(300), nullable=True, unique=False)
|
currentdistribusi = db.Column(db.String(300), nullable=True, unique=False)
|
||||||
|
# resethash = db.Column(db.String(300), nullable=True, unique=True)
|
||||||
|
# resettime = db.Column(db.DateTime)
|
||||||
tutor = db.Column(db.Boolean, default=False)
|
tutor = db.Column(db.Boolean, default=False)
|
||||||
admin = db.Column(db.Boolean, default=False)
|
admin = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user