start user page port
This commit is contained in:
		@@ -84,6 +84,6 @@ def create_app():
 | 
			
		||||
 | 
			
		||||
    @app.context_processor
 | 
			
		||||
    def inject_auth():
 | 
			
		||||
        return {"is_logged_in": is_logged_in, "get_active_user": get_active_user}
 | 
			
		||||
        return {"is_logged_in": is_logged_in, "get_active_user": get_active_user, "active_user": get_active_user()}
 | 
			
		||||
 | 
			
		||||
    return app
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
from .db import Model
 | 
			
		||||
from .db import Model, db
 | 
			
		||||
from .constants import PermissionLevel
 | 
			
		||||
 | 
			
		||||
class Users(Model):
 | 
			
		||||
@@ -19,6 +19,40 @@ class Users(Model):
 | 
			
		||||
    def is_default_avatar(self):
 | 
			
		||||
        return self.avatar_id == 1
 | 
			
		||||
 | 
			
		||||
    def get_latest_posts(self):
 | 
			
		||||
        q = """SELECT
 | 
			
		||||
                posts.id, posts.created_at, post_history.content, post_history.edited_at, threads.title AS thread_title, topics.name as topic_name, threads.slug as thread_slug
 | 
			
		||||
            FROM
 | 
			
		||||
                posts
 | 
			
		||||
            JOIN
 | 
			
		||||
                post_history ON posts.current_revision_id = post_history.id
 | 
			
		||||
            JOIN
 | 
			
		||||
                threads ON posts.thread_id = threads.id
 | 
			
		||||
            JOIN
 | 
			
		||||
                topics ON threads.topic_id = topics.id
 | 
			
		||||
            WHERE
 | 
			
		||||
                posts.user_id = ?
 | 
			
		||||
            ORDER BY posts.created_at DESC
 | 
			
		||||
            LIMIT 10"""
 | 
			
		||||
        return db.query(q, self.id)
 | 
			
		||||
 | 
			
		||||
    def get_post_stats(self):
 | 
			
		||||
        q = """SELECT
 | 
			
		||||
                COUNT(posts.id) AS post_count,
 | 
			
		||||
                COUNT(DISTINCT threads.id) AS thread_count,
 | 
			
		||||
                MAX(threads.title) FILTER (WHERE threads.created_at = latest.created_at) AS latest_thread_title,
 | 
			
		||||
                MAX(threads.slug) FILTER (WHERE threads.created_at = latest.created_at) AS latest_thread_slug
 | 
			
		||||
            FROM users
 | 
			
		||||
            LEFT JOIN posts ON posts.user_id = users.id
 | 
			
		||||
            LEFT JOIN threads ON threads.user_id = users.id
 | 
			
		||||
            LEFT JOIN (
 | 
			
		||||
                SELECT user_id, MAX(created_at) AS created_at
 | 
			
		||||
                FROM threads
 | 
			
		||||
                GROUP BY user_id
 | 
			
		||||
                ) latest ON latest.user_id = users.id
 | 
			
		||||
            WHERE users.id = ?"""
 | 
			
		||||
        return db.fetch_one(q, self.id)
 | 
			
		||||
 | 
			
		||||
class Topics(Model):
 | 
			
		||||
    table = "topics"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from flask import (
 | 
			
		||||
    Blueprint, render_template, request, redirect, url_for, flash, session
 | 
			
		||||
    Blueprint, render_template, request, redirect, url_for, flash, session, current_app
 | 
			
		||||
    )
 | 
			
		||||
from functools import wraps
 | 
			
		||||
from ..models import Users, Sessions
 | 
			
		||||
from ..constants import InfoboxKind, PermissionLevel
 | 
			
		||||
from ..auth import digest, verify
 | 
			
		||||
@@ -42,12 +43,67 @@ def validate_username(username):
 | 
			
		||||
    return bool(re.fullmatch(pattern, username))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def redirect_if_logged_in(*args, **kwargs):
 | 
			
		||||
    def decorator(view_func):
 | 
			
		||||
        @wraps(view_func)
 | 
			
		||||
        def wrapper(*view_args, **view_kwargs):
 | 
			
		||||
            if is_logged_in():
 | 
			
		||||
                # resolve callables
 | 
			
		||||
                processed_kwargs = {
 | 
			
		||||
                    k: v() if callable(v) else v
 | 
			
		||||
                    for k, v in kwargs.items()
 | 
			
		||||
                }
 | 
			
		||||
                endpoint = args[0] if args else processed_kwargs.get("endpoint")
 | 
			
		||||
                if endpoint.startswith("."):
 | 
			
		||||
                    blueprint = current_app.blueprints.get(view_func.__name__.split(".")[0])
 | 
			
		||||
                    if blueprint:
 | 
			
		||||
                        endpoint = endpoint.lstrip(".")
 | 
			
		||||
                        return redirect(url_for(f"{blueprint.name}.{endpoint}", **processed_kwargs))
 | 
			
		||||
                return redirect(url_for(*args, **processed_kwargs))
 | 
			
		||||
            return view_func(*view_args, **view_kwargs)
 | 
			
		||||
        return wrapper
 | 
			
		||||
    return decorator
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def login_required(view_func):
 | 
			
		||||
    @wraps(view_func)
 | 
			
		||||
    def wrapper(*args, **kwargs):
 | 
			
		||||
        if not is_logged_in():
 | 
			
		||||
            return redirect(url_for("users.log_in"))
 | 
			
		||||
        return view_func(*args, **kwargs)
 | 
			
		||||
    return wrapper
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def mod_only(*args, **kwargs):
 | 
			
		||||
    def decorator(view_func):
 | 
			
		||||
        @wraps(view_func)
 | 
			
		||||
        def wrapper(*view_args, **view_kwargs):
 | 
			
		||||
            if not get_active_user().is_mod():
 | 
			
		||||
                # resolve callables
 | 
			
		||||
                processed_kwargs = {
 | 
			
		||||
                    k: v() if callable(v) else v
 | 
			
		||||
                    for k, v in kwargs.items()
 | 
			
		||||
                }
 | 
			
		||||
                endpoint = args[0] if args else processed_kwargs.get("endpoint")
 | 
			
		||||
                if endpoint.startswith("."):
 | 
			
		||||
                    blueprint = current_app.blueprints.get(view_func.__name__.split(".")[0])
 | 
			
		||||
                    if blueprint:
 | 
			
		||||
                        endpoint = endpoint.lstrip(".")
 | 
			
		||||
                        return redirect(url_for(f"{blueprint.name}.{endpoint}", **processed_kwargs))
 | 
			
		||||
                return redirect(url_for(*args, **processed_kwargs))
 | 
			
		||||
            return view_func(*view_args, **view_kwargs)
 | 
			
		||||
        return wrapper
 | 
			
		||||
    return decorator
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/log_in")
 | 
			
		||||
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
 | 
			
		||||
def log_in():
 | 
			
		||||
    return render_template("users/log_in.html")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/log_in")
 | 
			
		||||
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
 | 
			
		||||
def log_in_post():
 | 
			
		||||
    target_user = Users.find({
 | 
			
		||||
        "username": request.form['username']
 | 
			
		||||
@@ -68,11 +124,13 @@ def log_in_post():
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/sign_up")
 | 
			
		||||
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
 | 
			
		||||
def sign_up():
 | 
			
		||||
    return render_template("users/sign_up.html")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/sign_up")
 | 
			
		||||
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
 | 
			
		||||
def sign_up_post():
 | 
			
		||||
    username = request.form['username']
 | 
			
		||||
    password = request.form['password']
 | 
			
		||||
@@ -112,19 +170,29 @@ def sign_up_post():
 | 
			
		||||
 | 
			
		||||
@bp.get("/<username>")
 | 
			
		||||
def page(username):
 | 
			
		||||
    return "stub"
 | 
			
		||||
    target_user = Users.find({"username": username})
 | 
			
		||||
    return render_template("users/user.html", target_user = target_user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/<username>/setings")
 | 
			
		||||
@login_required
 | 
			
		||||
def settings(username):
 | 
			
		||||
    return "stub"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/<username>/inbox")
 | 
			
		||||
@login_required
 | 
			
		||||
def inbox(username):
 | 
			
		||||
    return "stub"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/list")
 | 
			
		||||
@login_required
 | 
			
		||||
@mod_only(".page", username = lambda: get_active_user().username)
 | 
			
		||||
def user_list():
 | 
			
		||||
    return "stub"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/log_out")
 | 
			
		||||
def log_out():
 | 
			
		||||
    pass
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="UTF-8">
 | 
			
		||||
  {% if title %}
 | 
			
		||||
  {% if self.title() %}
 | 
			
		||||
    <title>Porom - {% block title %}{% endblock %}</title>
 | 
			
		||||
  {% else %}
 | 
			
		||||
    <title>Porom</title>
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
  {% endwith %}
 | 
			
		||||
  {% block content %}{% endblock %}
 | 
			
		||||
  <footer class="darkbg">
 | 
			
		||||
    <span>Porom commit</span>
 | 
			
		||||
    <span>Pyrom commit</span>
 | 
			
		||||
  </footer>
 | 
			
		||||
  <script src="/static/js/copy-code.js"></script>
 | 
			
		||||
  <script src="/static/js/ui.js"></script>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								app/templates/users/user.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								app/templates/users/user.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
{% extends 'base.html' %}
 | 
			
		||||
{% block title %}{{ target_user.username }}'s profile{% endblock %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="darkbg">
 | 
			
		||||
  <h1 class="thread-title"><i>{{ target_user.username }}</i>'s profile</h1>
 | 
			
		||||
  {% if active_user.id == target_user.id %}
 | 
			
		||||
    <div class="user-actions">
 | 
			
		||||
      <a class="linkbutton" href="{{ url_for("users.settings", username = active_user.username) }}">Settings</a>
 | 
			
		||||
      <form method="post" action="{{ url_for("users.log_out") }}">
 | 
			
		||||
        <input class="warn" type="submit" value="Log out">
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% if active_user.is_guest() %}
 | 
			
		||||
      <h2>You are a guest. A Moderator needs to approve your account before you will be able to post.</h2>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
  {% if active_user and active_user.is_mod() and not target_user.is_system() %}
 | 
			
		||||
    <h1 class="thread-title">Moderation controls</h1>
 | 
			
		||||
    {% if target_user.is_guest() %}
 | 
			
		||||
      <p>This user is a guest. They signed up on ... </p>
 | 
			
		||||
    {% else %}
 | 
			
		||||
      <p>This user signed up on ... and was confirmed on ...</p>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
<div>
 | 
			
		||||
  {% with stats = target_user.get_post_stats() %}
 | 
			
		||||
    <ul>
 | 
			
		||||
      <li>Posts created: {{ stats.post_count }}</li>
 | 
			
		||||
      <li>Threads started: {{ stats.thread_count }}</li>
 | 
			
		||||
      <li>Latest started thread: {{ stats.latest_thread_title }}
 | 
			
		||||
    </ul>
 | 
			
		||||
  {% endwith %}
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user