sign up
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
			
		||||
from flask import Blueprint
 | 
			
		||||
from flask import Blueprint, redirect, url_for
 | 
			
		||||
 | 
			
		||||
bp = Blueprint("app", __name__, url_prefix = "/")
 | 
			
		||||
 | 
			
		||||
@bp.route("/")
 | 
			
		||||
def hello_world():
 | 
			
		||||
    return f"<img src='static/avatars/default.webp'></img>"
 | 
			
		||||
def index():
 | 
			
		||||
    return redirect(url_for("topics.all_topics"))
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,11 @@ from flask import (
 | 
			
		||||
    Blueprint, render_template, request, redirect, url_for, flash, session
 | 
			
		||||
    )
 | 
			
		||||
from ..models import Users, Sessions
 | 
			
		||||
from ..constants import InfoboxKind
 | 
			
		||||
from ..constants import InfoboxKind, PermissionLevel
 | 
			
		||||
from ..auth import digest, verify
 | 
			
		||||
import secrets
 | 
			
		||||
import time
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
bp = Blueprint("users", __name__, url_prefix = "/users/")
 | 
			
		||||
 | 
			
		||||
@@ -23,6 +24,24 @@ def get_active_user():
 | 
			
		||||
    return Users.find({"id": sess.user_id})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_session(user_id):
 | 
			
		||||
    return Sessions.create({
 | 
			
		||||
        "key": secrets.token_hex(16),
 | 
			
		||||
        "user_id": user_id,
 | 
			
		||||
        "expires_at": int(time.time()) + 30 * 24 * 60 * 60,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_password(password):
 | 
			
		||||
    pattern = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,255}$'
 | 
			
		||||
    return bool(re.fullmatch(pattern, password))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_username(username):
 | 
			
		||||
    pattern = r'^[a-zA-Z0-9_-]{3,20}$'
 | 
			
		||||
    return bool(re.fullmatch(pattern, username))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/log_in")
 | 
			
		||||
def log_in():
 | 
			
		||||
    return render_template("users/log_in.html")
 | 
			
		||||
@@ -41,11 +60,7 @@ def log_in_post():
 | 
			
		||||
        flash("Incorrect username or password.", InfoboxKind.ERROR)
 | 
			
		||||
        return redirect(url_for("users.log_in"))
 | 
			
		||||
 | 
			
		||||
    session_obj = Sessions.create({
 | 
			
		||||
        "key": secrets.token_hex(16),
 | 
			
		||||
        "user_id": target_user.id,
 | 
			
		||||
        "expires_at": int(time.time()) + 30 * 24 * 60 * 60,
 | 
			
		||||
    })
 | 
			
		||||
    session_obj = create_session(target_user.id)
 | 
			
		||||
 | 
			
		||||
    session['pyrom_session_key'] = session_obj.key
 | 
			
		||||
    flash("Logged in!", InfoboxKind.INFO)
 | 
			
		||||
@@ -54,7 +69,45 @@ def log_in_post():
 | 
			
		||||
 | 
			
		||||
@bp.get("/sign_up")
 | 
			
		||||
def sign_up():
 | 
			
		||||
    return "not yet"
 | 
			
		||||
    return render_template("users/sign_up.html")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/sign_up")
 | 
			
		||||
def sign_up_post():
 | 
			
		||||
    username = request.form['username']
 | 
			
		||||
    password = request.form['password']
 | 
			
		||||
    password_confirm = request.form['password-confirm']
 | 
			
		||||
 | 
			
		||||
    if not validate_username(username):
 | 
			
		||||
        flash("Invalid username.", InfoboxKind.ERROR)
 | 
			
		||||
        return redirect(url_for("users.sign_up"))
 | 
			
		||||
 | 
			
		||||
    user_exists = Users.count({"username": username}) > 0
 | 
			
		||||
    if user_exists:
 | 
			
		||||
        flash(f"Username '{username}' is already taken.", InfoboxKind.ERROR)
 | 
			
		||||
        return redirect(url_for("users.sign_up"))
 | 
			
		||||
 | 
			
		||||
    if not validate_password(password):
 | 
			
		||||
        flash("Invalid password.", InfoboxKind.ERROR)
 | 
			
		||||
        return redirect(url_for("users.sign_up"))
 | 
			
		||||
 | 
			
		||||
    if password != password_confirm:
 | 
			
		||||
        flash("Passwords do not match.", InfoboxKind.ERROR)
 | 
			
		||||
        return redirect(url_for("users.sign_up"))
 | 
			
		||||
 | 
			
		||||
    hashed = digest(password)
 | 
			
		||||
 | 
			
		||||
    new_user = Users.create({
 | 
			
		||||
        "username": username,
 | 
			
		||||
        "password_hash": hashed,
 | 
			
		||||
        "permission": PermissionLevel.GUEST.value,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    session_obj = create_session(new_user.id)
 | 
			
		||||
 | 
			
		||||
    session['pyrom_session_key'] = session_obj.key
 | 
			
		||||
    flash("Signed up successfully!", InfoboxKind.INFO)
 | 
			
		||||
    return redirect(url_for("users.sign_up"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/<username>")
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
{% block title %}Log in{% endblock %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="darkbg login-container">
 | 
			
		||||
  <h1>Log In</h1>
 | 
			
		||||
  <h1>Log in</h1>
 | 
			
		||||
  <form method="post">
 | 
			
		||||
    <label for="username">Username</label><br>
 | 
			
		||||
    <input type="text" id="username" name="username" required autocomplete="username"><br>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
{% extends 'base.html' %}
 | 
			
		||||
{% block title %}Sign up{% endblock %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="darkbg login-container">
 | 
			
		||||
  <h1>Sign up</h1>
 | 
			
		||||
  <form method="post">
 | 
			
		||||
    <label for="username">Username</label><br>
 | 
			
		||||
    <input type="text" id="username" name="username" pattern="[a-zA-Z0-9_-]{3,20}" title="3-20 characters. Only upper and lowercase letters, digits, hyphens, and underscores" required autocomplete="username"><br>
 | 
			
		||||
    <label for="password">Password</label>
 | 
			
		||||
    <input type="password" id="password" name="password" pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,255}" title="10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces" required autocomplete="new-password"><br>
 | 
			
		||||
    <label for="password-confirm">Confirm Password</label>
 | 
			
		||||
    <input type="password" id="password-confirm" name="password-confirm" pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,255}" title="10+ chars with: 1 uppercase, 1 lowercase, 1 number, 1 special char, and no spaces" required autocomplete="new-password"><br>
 | 
			
		||||
    <input type="submit" value="Sign up">
 | 
			
		||||
  </form>
 | 
			
		||||
  <span>After you sign up, a moderator will need to confirm your account before you will be allowed to post.</span>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user