mgt c10 checkpoint with debug
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
				
			|||||||
 | 
					from flask import render_template
 | 
				
			||||||
from flask_mail import Message
 | 
					from flask_mail import Message
 | 
				
			||||||
from app import mail
 | 
					from app import mail, app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_email(subject, sender, recipients, text_body, html_body):
 | 
					def send_email(subject, sender, recipients, text_body, html_body):
 | 
				
			||||||
    msg = Message(subject, sender=sender, recipients=recipients)
 | 
					    msg = Message(subject, sender=sender, recipients=recipients)
 | 
				
			||||||
@@ -7,3 +8,15 @@ def send_email(subject, sender, recipients, text_body, html_body):
 | 
				
			|||||||
    msg.html = html_body
 | 
					    msg.html = html_body
 | 
				
			||||||
    mail.send(msg)
 | 
					    mail.send(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def send_password_reset_email(user):
 | 
				
			||||||
 | 
					    token = user.get_reset_password_token()
 | 
				
			||||||
 | 
					    hostname = app.config['REAL_HOSTNAME']
 | 
				
			||||||
 | 
					    send_email('[Blog] Reset Password',
 | 
				
			||||||
 | 
					               sender=app.config['ADMINS'][0],
 | 
				
			||||||
 | 
					               recipients=[user.email],
 | 
				
			||||||
 | 
					               text_body=render_template('email/reset_password.txt', hostname=hostname, user=user, token=token),
 | 
				
			||||||
 | 
					               html_body=render_template('email/reset_password.html', hostname=hostname, user=user, token=token))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,17 +17,20 @@ class RegistrationForm(FlaskForm):
 | 
				
			|||||||
    password = PasswordField('Password', validators=[DataRequired()])
 | 
					    password = PasswordField('Password', validators=[DataRequired()])
 | 
				
			||||||
    password2 = PasswordField('Repeat Password', validators=[DataRequired()])
 | 
					    password2 = PasswordField('Repeat Password', validators=[DataRequired()])
 | 
				
			||||||
    submit = SubmitField('Register')
 | 
					    submit = SubmitField('Register')
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def validate_username(self, username):
 | 
					    def validate_username(self, username):
 | 
				
			||||||
        user = db.session.scalar(sa.select(User).where(User.username == username.data))
 | 
					        user = db.session.scalar(sa.select(User).where(User.username == username.data))
 | 
				
			||||||
        if user is not None:
 | 
					        if user is not None:
 | 
				
			||||||
            raise ValidationError('Please use a different username.')
 | 
					            raise ValidationError('Please use a different username.')
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def validate_email(self, email):
 | 
					    def validate_email(self, email):
 | 
				
			||||||
        user = db.session.scalar(sa.select(User).where(User.email == email.data))
 | 
					        user = db.session.scalar(sa.select(User).where(User.email == email.data))
 | 
				
			||||||
        if user is not None:
 | 
					        if user is not None:
 | 
				
			||||||
            raise ValidationError('Please use a different email address.')
 | 
					            raise ValidationError('Please use a different email address.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResetPasswordForm(FlaskForm):
 | 
				
			||||||
 | 
					    password = PasswordField('Password', validators=[DataRequired()])
 | 
				
			||||||
 | 
					    password2 = PasswordField('Repeat Password', validators=[DataRequired()])
 | 
				
			||||||
 | 
					    submit = SubmitField('Request Reset')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EditProfileForm(FlaskForm):
 | 
					class EditProfileForm(FlaskForm):
 | 
				
			||||||
    username = StringField('Username', validators=[DataRequired()])
 | 
					    username = StringField('Username', validators=[DataRequired()])
 | 
				
			||||||
    about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
 | 
					    about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,17 @@
 | 
				
			|||||||
import os
 | 
					 | 
				
			||||||
from datetime import datetime, timezone
 | 
					from datetime import datetime, timezone
 | 
				
			||||||
from typing import Optional
 | 
					from typing import Optional
 | 
				
			||||||
import sqlalchemy as sa
 | 
					import sqlalchemy as sa
 | 
				
			||||||
import sqlalchemy.orm as so
 | 
					import sqlalchemy.orm as so
 | 
				
			||||||
from werkzeug.security import generate_password_hash, check_password_hash
 | 
					from werkzeug.security import generate_password_hash, check_password_hash
 | 
				
			||||||
import pydenticon, hashlib, base64
 | 
					import os, pydenticon, hashlib, base64, jwt
 | 
				
			||||||
 | 
					from time import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from app import db, login
 | 
					from app import db, login, app
 | 
				
			||||||
from flask_login import UserMixin
 | 
					from flask_login import UserMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#debug
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
followers = sa.Table(
 | 
					followers = sa.Table(
 | 
				
			||||||
        'followers',
 | 
					        'followers',
 | 
				
			||||||
        db.metadata,
 | 
					        db.metadata,
 | 
				
			||||||
@@ -39,15 +42,31 @@ class User(UserMixin, db.Model):
 | 
				
			|||||||
        self.password_hash = generate_password_hash(password)
 | 
					        self.password_hash = generate_password_hash(password)
 | 
				
			||||||
    def check_password(self, password):
 | 
					    def check_password(self, password):
 | 
				
			||||||
        return check_password_hash(self.password_hash, password)
 | 
					        return check_password_hash(self.password_hash, password)
 | 
				
			||||||
 | 
					    def get_reset_password_token(self, expires_in=600):
 | 
				
			||||||
 | 
					        token = jwt.encode({'reset_password': self.id, 'exp': time() + expires_in},
 | 
				
			||||||
 | 
					                          app.config['SECRET_KEY'], algorithm='HS256')
 | 
				
			||||||
 | 
					        return token
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def verify_reset_password_token(token):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            id = jwt.decode(token,
 | 
				
			||||||
 | 
					                            app.config['SECRET_KEY'], algorithms='HS256')['reset_password']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        return db.session.get(User, id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def gen_avatar(self, write_png=True):
 | 
					    def gen_avatar(self, write_png=True):
 | 
				
			||||||
        foreground = [ "rgb(45,79,255)",
 | 
					        foreground = ['#ACE1AF',
 | 
				
			||||||
               "rgb(254,180,44)",
 | 
					                      '#ACC4E1',
 | 
				
			||||||
               "rgb(226,121,234)",
 | 
					                      '#E1ACDE',
 | 
				
			||||||
               "rgb(30,179,253)",
 | 
					                      '#E1CAAC',
 | 
				
			||||||
               "rgb(232,77,65)",
 | 
					                      '#AFFF00',
 | 
				
			||||||
               "rgb(49,203,115)",
 | 
					                      '#00FFCF',
 | 
				
			||||||
               "rgb(141,69,170)" ]
 | 
					                      '#5000FF',
 | 
				
			||||||
        background = "rgb(22,22,22)"
 | 
					                      '#FF0030']
 | 
				
			||||||
 | 
					                      
 | 
				
			||||||
 | 
					        background = '#151515'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        digest = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest()
 | 
					        digest = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest()
 | 
				
			||||||
        basedir = os.path.abspath(os.path.dirname(__file__))
 | 
					        basedir = os.path.abspath(os.path.dirname(__file__))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,12 @@ 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, ResetPasswordRequestForm
 | 
					from app.forms import LoginForm, RegistrationForm, EditProfileForm, EmptyForm, PostForm, ResetPasswordRequestForm, ResetPasswordForm
 | 
				
			||||||
from app.models import User, Post
 | 
					from app.models import User, Post
 | 
				
			||||||
#from app.email import send_password_reset_email
 | 
					from app.email import send_password_reset_email
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#debug:
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.before_request
 | 
					@app.before_request
 | 
				
			||||||
def before_request():
 | 
					def before_request():
 | 
				
			||||||
@@ -84,6 +87,25 @@ def register():
 | 
				
			|||||||
        return redirect(url_for('login'))
 | 
					        return redirect(url_for('login'))
 | 
				
			||||||
    return render_template('register.html', title='Register', form=form)
 | 
					    return render_template('register.html', title='Register', form=form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route('/reset_password/<token>', methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def reset_password(token):
 | 
				
			||||||
 | 
					    if current_user.is_authenticated:
 | 
				
			||||||
 | 
					        print('rp user is authed', file=sys.stderr)
 | 
				
			||||||
 | 
					        return redirect(url_for('index'))
 | 
				
			||||||
 | 
					    user = User.verify_reset_password_token(token)
 | 
				
			||||||
 | 
					    if not user:
 | 
				
			||||||
 | 
					        print('rp not user', file=sys.stderr)
 | 
				
			||||||
 | 
					        return redirect(url_for('index'))
 | 
				
			||||||
 | 
					    form = ResetPasswordForm()
 | 
				
			||||||
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
 | 
					        print('rp validated', file=sys.stderr)
 | 
				
			||||||
 | 
					        user.set_password(form.password.data)
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					        flash('Your password has been reset.')
 | 
				
			||||||
 | 
					        return redirect(url_for('login'))
 | 
				
			||||||
 | 
					    return render_template('reset_password.html', form=form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/user/<username>')
 | 
					@app.route('/user/<username>')
 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def user(username):
 | 
					def user(username):
 | 
				
			||||||
@@ -153,11 +175,14 @@ def unfollow(username):
 | 
				
			|||||||
@app.route('/reset_password_request', methods=['GET', 'POST'])
 | 
					@app.route('/reset_password_request', methods=['GET', 'POST'])
 | 
				
			||||||
def reset_password_request():
 | 
					def reset_password_request():
 | 
				
			||||||
    if current_user.is_authenticated:
 | 
					    if current_user.is_authenticated:
 | 
				
			||||||
 | 
					        print('rpr user is authed', file=sys.stderr)
 | 
				
			||||||
        return redirect(url_for('index'))
 | 
					        return redirect(url_for('index'))
 | 
				
			||||||
    form = ResetPasswordRequestForm()
 | 
					    form = ResetPasswordRequestForm()
 | 
				
			||||||
    if form.validate_on_submit():
 | 
					    if form.validate_on_submit():
 | 
				
			||||||
 | 
					        print('rpr form validated', file=sys.stderr)
 | 
				
			||||||
        user = db.session.scalar(sa.select(User).where(User.email == form.email.data))
 | 
					        user = db.session.scalar(sa.select(User).where(User.email == form.email.data))
 | 
				
			||||||
        if user:
 | 
					        if user:
 | 
				
			||||||
 | 
					            print('rpr if user', file=sys.stderr)
 | 
				
			||||||
            send_password_reset_email(user)
 | 
					            send_password_reset_email(user)
 | 
				
			||||||
        flash('Password reset sent.')
 | 
					        flash('Password reset sent.')
 | 
				
			||||||
        return redirect(url_for('login'))
 | 
					        return redirect(url_for('login'))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								backend/app/templates/email/reset_password.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								backend/app/templates/email/reset_password.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
						<body>
 | 
				
			||||||
 | 
							<p>User {{ user.username }} requested password reset.</p>
 | 
				
			||||||
 | 
							<p>Reset link:</p>
 | 
				
			||||||
 | 
							<p><a href="{{ hostname }}{{ url_for('reset_password', token=token) }}">click here</a>
 | 
				
			||||||
 | 
							<p>If you did not request this, ignore this message.</p>
 | 
				
			||||||
 | 
						</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								backend/app/templates/email/reset_password.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								backend/app/templates/email/reset_password.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					User {{ user.username }} requested password reset.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Reset link follows.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{ hostname }}{{ url_for('reset_password', token=token) }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you did not request this, ignore this message.
 | 
				
			||||||
							
								
								
									
										26
									
								
								backend/app/templates/reset_password.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								backend/app/templates/reset_password.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<h1>Reset Your Password</h1>
 | 
				
			||||||
 | 
						<form action="" method="post">
 | 
				
			||||||
 | 
							{{ form.hidden_tag() }}
 | 
				
			||||||
 | 
							<p>
 | 
				
			||||||
 | 
								{{ form.password.label }}
 | 
				
			||||||
 | 
								{{ form.password(size=32) }}
 | 
				
			||||||
 | 
								{% for error in form.password.errors %}
 | 
				
			||||||
 | 
								<span style="color: red;">[{{ error }}]</span>
 | 
				
			||||||
 | 
								{% endfor %}
 | 
				
			||||||
 | 
							</p>
 | 
				
			||||||
 | 
							<p>
 | 
				
			||||||
 | 
								{{ form.password2.label }}
 | 
				
			||||||
 | 
								{{ form.password2(size=32) }}
 | 
				
			||||||
 | 
								{% for error in form.password2.errors %}
 | 
				
			||||||
 | 
								<span style="color: red;">[{{ error }}]</span>
 | 
				
			||||||
 | 
								{% endfor %}
 | 
				
			||||||
 | 
							</p>
 | 
				
			||||||
 | 
							<p>{{ form.submit() }}</p>
 | 
				
			||||||
 | 
						</form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@@ -4,9 +4,9 @@ basedir = os.path.abspath(os.path.dirname(__file__))
 | 
				
			|||||||
# Remove or fallbacks for prod
 | 
					# Remove or fallbacks for prod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Config:
 | 
					class Config:
 | 
				
			||||||
    SECRET_KEY = os.environ.get('FLASK_SECRET_KEY') or 'flasksk'
 | 
					    SECRET_KEY = os.environ.get('DOTENV_FLASK_SECRET_KEY')
 | 
				
			||||||
    #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('DOTENV_MYSQL_PASSWORD') + '@db:3306/flask'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MAIL_SERVER = 'pmb'
 | 
					    MAIL_SERVER = 'pmb'
 | 
				
			||||||
    #MAIL_SERVER = ''
 | 
					    #MAIL_SERVER = ''
 | 
				
			||||||
@@ -14,8 +14,10 @@ class Config:
 | 
				
			|||||||
    MAIL_USE_TLS = False
 | 
					    MAIL_USE_TLS = False
 | 
				
			||||||
    MAIL_USERNAME = ''
 | 
					    MAIL_USERNAME = ''
 | 
				
			||||||
    MAIL_PASSWORD = ''
 | 
					    MAIL_PASSWORD = ''
 | 
				
			||||||
    ADMINS = [os.environ.get('ADMIN_EMAIL')]
 | 
					    ADMINS = [os.environ.get('DOTENV_ADMIN_EMAIL')]
 | 
				
			||||||
    FROM_ADDRESS = os.environ.get('FROM_ADDRESS')
 | 
					    FROM_ADDRESS = os.environ.get('DOTENV_FROM_ADDRESS')
 | 
				
			||||||
 | 
					    REAL_HOSTNAME = os.environ.get('DOTENV_REAL_HOSTNAME')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DC_LOGGING = True
 | 
					    DC_LOGGING = True
 | 
				
			||||||
    POSTS_PER_PAGE=5
 | 
					    POSTS_PER_PAGE=5
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								compose.yaml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								compose.yaml
									
									
									
									
									
								
							@@ -37,11 +37,14 @@ services:
 | 
				
			|||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      - MYSQL_USER=flasku
 | 
					      - MYSQL_USER=flasku
 | 
				
			||||||
      #- MYSQL_PASSWORD=flaskp
 | 
					      #- MYSQL_PASSWORD=flaskp
 | 
				
			||||||
      - MYSQL_PASSWORD=${DOTENV_MYSQL_FLASK_PASSWORD}
 | 
					      - DOTENV_MYSQL_PASSWORD=${DOTENV_MYSQL_FLASK_PASSWORD}
 | 
				
			||||||
      - TOKEN_I=${DOTENV_TOKEN_I}
 | 
					      - DOTENV_FLASK_SECRET_KEY=${FLASK_SECRET_KEY}
 | 
				
			||||||
      - TOKEN_C=${DOTENV_TOKEN_C}
 | 
					      - DOTENV_TOKEN_I=${FLASK_TOKEN_I}
 | 
				
			||||||
      - ADMIN_EMAIL=${ADMIN_EMAIL}
 | 
					      - DOTENV_TOKEN_C=${FLASK_TOKEN_C}
 | 
				
			||||||
      - FROM_ADDRESS=${GITEA_MAIL_FROM}
 | 
					      - DOTENV_ADMIN_EMAIL=${FLASK_ADMIN_EMAIL}
 | 
				
			||||||
 | 
					      - DOTENV_FROM_ADDRESS=${FLASK_MAIL_FROM}
 | 
				
			||||||
 | 
					      - DOTENV_JWT_PHRASE=${FLASK_JWT_PHRASE}
 | 
				
			||||||
 | 
					      - DOTENV_REAL_HOSTNAME=${FLASK_REAL_HOSTNAME}
 | 
				
			||||||
    #ports:
 | 
					    #ports:
 | 
				
			||||||
    #  - 8000:8000
 | 
					    #  - 8000:8000
 | 
				
			||||||
    expose:
 | 
					    expose:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user