flask site buildout #2

Merged
finn merged 25 commits from mgtut1 into master 2024-08-05 08:41:03 +00:00
10 changed files with 58 additions and 10 deletions
Showing only changes of commit ed9df4db6f - Show all commits

View File

@ -10,7 +10,7 @@ RUN apt update && apt install -y \
WORKDIR /code WORKDIR /code
COPY requirements.txt /code COPY requirements.txt /code
RUN target=/root/.cache/pip \ RUN target=/root/.cache/pip \
pip3 install -r requirements.txt pip3 install --root-user-action=ignore -q -r requirements.txt
# Need to make this explicit as part of expansion, no migrations or venv # Need to make this explicit as part of expansion, no migrations or venv
COPY . . COPY . .

View File

@ -18,6 +18,8 @@ pip install flask-migrate
pip install flask-login pip install flask-login
pip install email-validator pip install email-validator
pip install pydenticon pip install pydenticon
pip install flask-mail
pip install pyjwt
Prod only, require sys packages: Prod only, require sys packages:
pip install mariadb pip install mariadb
pip install uwsgi pip install uwsgi

View File

@ -5,6 +5,7 @@ from flask_migrate import Migrate
from flask_login import LoginManager from flask_login import LoginManager
import logging, sys import logging, sys
from logging.handlers import SMTPHandler from logging.handlers import SMTPHandler
from flask_mail import Mail
app = Flask(__name__) app = Flask(__name__)
app.config.from_object(Config) app.config.from_object(Config)
@ -12,6 +13,7 @@ db = SQLAlchemy(app)
migrate = Migrate(app, db) migrate = Migrate(app, db)
login = LoginManager(app) login = LoginManager(app)
login.login_view = 'login' login.login_view = 'login'
mail=Mail(app)
if not app.debug: if not app.debug:
if app.config['MAIL_SERVER']: if app.config['MAIL_SERVER']:

9
backend/app/email.py Normal file
View File

@ -0,0 +1,9 @@
from flask_mail import Message
from app import mail
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
mail.send(msg)

View File

@ -43,6 +43,10 @@ class EditProfileForm(FlaskForm):
if user is not None: if user is not None:
raise ValidationError('Please use a different username.') raise ValidationError('Please use a different username.')
class ResetPasswordRequestForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
submit = SubmitField('Request Password Reset')
class PostForm(FlaskForm): class PostForm(FlaskForm):
post = TextAreaField('Post:', validators=[DataRequired(), Length(min=1, max=140)]) post = TextAreaField('Post:', validators=[DataRequired(), Length(min=1, max=140)])
submit = SubmitField('Submit') submit = SubmitField('Submit')

View File

@ -5,8 +5,9 @@ from datetime import datetime, timezone
import sqlalchemy as sa import sqlalchemy as sa
from app import app, db from app import app, db
from app.forms import LoginForm, RegistrationForm, EditProfileForm, EmptyForm, PostForm from app.forms import LoginForm, RegistrationForm, EditProfileForm, EmptyForm, PostForm, ResetPasswordRequestForm
from app.models import User, Post from app.models import User, Post
#from app.email import send_password_reset_email
@app.before_request @app.before_request
def before_request(): def before_request():
@ -149,4 +150,17 @@ def unfollow(username):
else: else:
return redirect(url_for('index')) return redirect(url_for('index'))
@app.route('/reset_password_request', methods=['GET', 'POST'])
def reset_password_request():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = db.session.scalar(sa.select(User).where(User.email == form.email.data))
if user:
send_password_reset_email(user)
flash('Password reset sent.')
return redirect(url_for('login'))
return render_template('reset_password_request.html', title='Reset Password', form=form)

View File

@ -23,6 +23,7 @@
</form> </form>
<p><a href="{{ url_for('register') }}">Register Here</a></p> <p><a href="{{ url_for('register') }}">Register Here</a></p>
<p><a href="{{ url_for('reset_password_request') }}">Reset Password</a></p>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% block content %}
<h1>Reset Password</h1>
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
{{ form.email.label }}<br>
{{ form.email(size=64) }}<br>
{% for error in form.email.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}

View File

@ -8,8 +8,8 @@ class Config:
#SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'zapp.db') #SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'zapp.db')
SQLALCHEMY_DATABASE_URI = 'mariadb+mariadbconnector://flasku:' + os.environ.get('MYSQL_PASSWORD') + '@db:3306/flask' SQLALCHEMY_DATABASE_URI = 'mariadb+mariadbconnector://flasku:' + os.environ.get('MYSQL_PASSWORD') + '@db:3306/flask'
#MAIL_SERVER = 'pmb' MAIL_SERVER = 'pmb'
MAIL_SERVER = '' #MAIL_SERVER = ''
MAIL_PORT = 25 MAIL_PORT = 25
MAIL_USE_TLS = False MAIL_USE_TLS = False
MAIL_USERNAME = '' MAIL_USERNAME = ''

View File

@ -5,6 +5,7 @@ dnspython==2.6.1
email_validator==2.2.0 email_validator==2.2.0
Flask==3.0.3 Flask==3.0.3
Flask-Login==0.6.3 Flask-Login==0.6.3
Flask-Mail==0.10.0
Flask-Migrate==4.0.7 Flask-Migrate==4.0.7
Flask-SQLAlchemy==3.1.1 Flask-SQLAlchemy==3.1.1
Flask-WTF==1.2.1 Flask-WTF==1.2.1
@ -13,17 +14,15 @@ idna==3.7
itsdangerous==2.2.0 itsdangerous==2.2.0
Jinja2==3.1.4 Jinja2==3.1.4
Mako==1.3.5 Mako==1.3.5
mariadb==1.1.10
MarkupSafe==2.1.5 MarkupSafe==2.1.5
packaging==24.1
pillow==10.4.0 pillow==10.4.0
pydenticon==0.3.1 pydenticon==0.3.1
PyJWT==2.9.0
python-dotenv==1.0.1 python-dotenv==1.0.1
SQLAlchemy==2.0.31 SQLAlchemy==2.0.31
typing_extensions==4.12.2 typing_extensions==4.12.2
uWSGI==2.0.26
Werkzeug==3.0.3 Werkzeug==3.0.3
WTForms==3.1.2 WTForms==3.1.2
mariadb==1.1.10
packaging==24.1
setuptools==72.1.0
uWSGI==2.0.26
wheel==0.43.0