Prune unverified accounts
This commit is contained in:
58
app.py
58
app.py
@@ -102,14 +102,14 @@ def force_http_scheme():
|
||||
if app.debug or os.environ.get('FLASK_ENV') == 'debug':
|
||||
from flask import url_for as original_url_for
|
||||
import functools
|
||||
|
||||
|
||||
@functools.wraps(original_url_for)
|
||||
def url_for_http(*args, **kwargs):
|
||||
# Force _scheme to http if _external is True
|
||||
if kwargs.get('_external'):
|
||||
kwargs['_scheme'] = 'http'
|
||||
return original_url_for(*args, **kwargs)
|
||||
|
||||
|
||||
app.jinja_env.globals['url_for'] = url_for_http
|
||||
|
||||
# Configure Flask-Mail
|
||||
@@ -365,7 +365,7 @@ def robots_txt():
|
||||
def sitemap_xml():
|
||||
"""Generate XML sitemap for search engines"""
|
||||
pages = []
|
||||
|
||||
|
||||
# Static pages accessible without login
|
||||
static_pages = [
|
||||
{'loc': '/', 'priority': '1.0', 'changefreq': 'daily'},
|
||||
@@ -373,7 +373,7 @@ def sitemap_xml():
|
||||
{'loc': '/register', 'priority': '0.9', 'changefreq': 'monthly'},
|
||||
{'loc': '/forgot_password', 'priority': '0.5', 'changefreq': 'monthly'},
|
||||
]
|
||||
|
||||
|
||||
for page in static_pages:
|
||||
pages.append({
|
||||
'loc': request.host_url[:-1] + page['loc'],
|
||||
@@ -381,10 +381,10 @@ def sitemap_xml():
|
||||
'priority': page['priority'],
|
||||
'changefreq': page['changefreq']
|
||||
})
|
||||
|
||||
|
||||
sitemap_xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||
sitemap_xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
|
||||
|
||||
|
||||
for page in pages:
|
||||
sitemap_xml += ' <url>\n'
|
||||
sitemap_xml += f' <loc>{page["loc"]}</loc>\n'
|
||||
@@ -392,9 +392,9 @@ def sitemap_xml():
|
||||
sitemap_xml += f' <changefreq>{page["changefreq"]}</changefreq>\n'
|
||||
sitemap_xml += f' <priority>{page["priority"]}</priority>\n'
|
||||
sitemap_xml += ' </url>\n'
|
||||
|
||||
|
||||
sitemap_xml += '</urlset>'
|
||||
|
||||
|
||||
return Response(sitemap_xml, mimetype='application/xml')
|
||||
|
||||
@app.route('/site.webmanifest')
|
||||
@@ -986,11 +986,11 @@ def forgot_password():
|
||||
"""Handle forgot password requests"""
|
||||
if request.method == 'POST':
|
||||
username_or_email = request.form.get('username_or_email', '').strip()
|
||||
|
||||
|
||||
if not username_or_email:
|
||||
flash('Please enter your username or email address.', 'error')
|
||||
return render_template('forgot_password.html', title='Forgot Password')
|
||||
|
||||
|
||||
# Try to find user by username or email
|
||||
user = User.query.filter(
|
||||
db.or_(
|
||||
@@ -998,11 +998,11 @@ def forgot_password():
|
||||
User.email == username_or_email
|
||||
)
|
||||
).first()
|
||||
|
||||
|
||||
if user and user.email:
|
||||
# Generate reset token
|
||||
token = user.generate_password_reset_token()
|
||||
|
||||
|
||||
# Send reset email
|
||||
reset_url = url_for('reset_password', token=token, _external=True)
|
||||
msg = Message(
|
||||
@@ -1023,7 +1023,7 @@ If you did not request a password reset, please ignore this email.
|
||||
Best regards,
|
||||
The {g.branding.app_name if g.branding else "TimeTrack"} Team
|
||||
'''
|
||||
|
||||
|
||||
try:
|
||||
mail.send(msg)
|
||||
logger.info(f"Password reset email sent to user {user.username}")
|
||||
@@ -1031,11 +1031,11 @@ The {g.branding.app_name if g.branding else "TimeTrack"} Team
|
||||
logger.error(f"Failed to send password reset email: {str(e)}")
|
||||
flash('Failed to send reset email. Please contact support.', 'error')
|
||||
return render_template('forgot_password.html', title='Forgot Password')
|
||||
|
||||
|
||||
# Always show success message to prevent user enumeration
|
||||
flash('If an account exists with that username or email address, we have sent a password reset link.', 'success')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
|
||||
return render_template('forgot_password.html', title='Forgot Password')
|
||||
|
||||
@app.route('/reset_password/<token>', methods=['GET', 'POST'])
|
||||
@@ -1043,42 +1043,42 @@ def reset_password(token):
|
||||
"""Handle password reset with token"""
|
||||
# Find user by reset token
|
||||
user = User.query.filter_by(password_reset_token=token).first()
|
||||
|
||||
|
||||
if not user or not user.verify_password_reset_token(token):
|
||||
flash('Invalid or expired reset link.', 'error')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
password = request.form.get('password')
|
||||
confirm_password = request.form.get('confirm_password')
|
||||
|
||||
|
||||
# Validate input
|
||||
error = None
|
||||
if not password:
|
||||
error = 'Password is required'
|
||||
elif password != confirm_password:
|
||||
error = 'Passwords do not match'
|
||||
|
||||
|
||||
# Validate password strength
|
||||
if not error:
|
||||
validator = PasswordValidator()
|
||||
is_valid, password_errors = validator.validate(password)
|
||||
if not is_valid:
|
||||
error = password_errors[0]
|
||||
|
||||
|
||||
if error:
|
||||
flash(error, 'error')
|
||||
return render_template('reset_password.html', token=token, title='Reset Password')
|
||||
|
||||
|
||||
# Update password
|
||||
user.set_password(password)
|
||||
user.clear_password_reset_token()
|
||||
db.session.commit()
|
||||
|
||||
|
||||
logger.info(f"Password reset successful for user {user.username}")
|
||||
flash('Your password has been reset successfully. Please log in with your new password.', 'success')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
|
||||
return render_template('reset_password.html', token=token, title='Reset Password')
|
||||
|
||||
@app.route('/dashboard')
|
||||
@@ -2931,14 +2931,14 @@ def render_markdown():
|
||||
try:
|
||||
data = request.get_json()
|
||||
content = data.get('content', '')
|
||||
|
||||
|
||||
if not content:
|
||||
return jsonify({'html': '<p class="preview-placeholder">Start typing to see the preview...</p>'})
|
||||
|
||||
|
||||
# Parse frontmatter and extract body
|
||||
from frontmatter_utils import parse_frontmatter
|
||||
metadata, body = parse_frontmatter(content)
|
||||
|
||||
|
||||
# Render markdown to HTML
|
||||
try:
|
||||
import markdown
|
||||
@@ -2947,13 +2947,13 @@ def render_markdown():
|
||||
except ImportError:
|
||||
# Fallback if markdown not installed
|
||||
html = f'<pre>{body}</pre>'
|
||||
|
||||
|
||||
return jsonify({'html': html})
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error rendering markdown: {str(e)}")
|
||||
return jsonify({'html': '<p class="error">Error rendering markdown</p>'})
|
||||
|
||||
if __name__ == '__main__':
|
||||
port = int(os.environ.get('PORT', 5000))
|
||||
app.run(debug=True, host='0.0.0.0', port=port)
|
||||
app.run(debug=True, host='0.0.0.0', port=port)
|
||||
|
||||
Reference in New Issue
Block a user