start user page port

This commit is contained in:
Lera Elvoé 2025-06-30 12:28:10 +03:00
parent bd56310067
commit fd257e701f
Signed by: yagich
SSH Key Fingerprint: SHA256:6xjGb6uA7lAVcULa7byPEN//rQ0wPoG+UzYVMfZnbvc
5 changed files with 143 additions and 6 deletions

View File

@ -84,6 +84,6 @@ def create_app():
@app.context_processor @app.context_processor
def inject_auth(): 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 return app

View File

@ -1,4 +1,4 @@
from .db import Model from .db import Model, db
from .constants import PermissionLevel from .constants import PermissionLevel
class Users(Model): class Users(Model):
@ -19,6 +19,40 @@ class Users(Model):
def is_default_avatar(self): def is_default_avatar(self):
return self.avatar_id == 1 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): class Topics(Model):
table = "topics" table = "topics"

View File

@ -1,6 +1,7 @@
from flask import ( 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 ..models import Users, Sessions
from ..constants import InfoboxKind, PermissionLevel from ..constants import InfoboxKind, PermissionLevel
from ..auth import digest, verify from ..auth import digest, verify
@ -42,12 +43,67 @@ def validate_username(username):
return bool(re.fullmatch(pattern, 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") @bp.get("/log_in")
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
def log_in(): def log_in():
return render_template("users/log_in.html") return render_template("users/log_in.html")
@bp.post("/log_in") @bp.post("/log_in")
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
def log_in_post(): def log_in_post():
target_user = Users.find({ target_user = Users.find({
"username": request.form['username'] "username": request.form['username']
@ -68,11 +124,13 @@ def log_in_post():
@bp.get("/sign_up") @bp.get("/sign_up")
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
def sign_up(): def sign_up():
return render_template("users/sign_up.html") return render_template("users/sign_up.html")
@bp.post("/sign_up") @bp.post("/sign_up")
@redirect_if_logged_in(".page", username = lambda: get_active_user().username)
def sign_up_post(): def sign_up_post():
username = request.form['username'] username = request.form['username']
password = request.form['password'] password = request.form['password']
@ -112,19 +170,29 @@ def sign_up_post():
@bp.get("/<username>") @bp.get("/<username>")
def page(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") @bp.get("/<username>/setings")
@login_required
def settings(username): def settings(username):
return "stub" return "stub"
@bp.get("/<username>/inbox") @bp.get("/<username>/inbox")
@login_required
def inbox(username): def inbox(username):
return "stub" return "stub"
@bp.get("/list") @bp.get("/list")
@login_required
@mod_only(".page", username = lambda: get_active_user().username)
def user_list(): def user_list():
return "stub" return "stub"
@bp.post("/log_out")
def log_out():
pass

View File

@ -3,7 +3,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
{% if title %} {% if self.title() %}
<title>Porom - {% block title %}{% endblock %}</title> <title>Porom - {% block title %}{% endblock %}</title>
{% else %} {% else %}
<title>Porom</title> <title>Porom</title>
@ -21,7 +21,7 @@
{% endwith %} {% endwith %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
<footer class="darkbg"> <footer class="darkbg">
<span>Porom commit</span> <span>Pyrom commit</span>
</footer> </footer>
<script src="/static/js/copy-code.js"></script> <script src="/static/js/copy-code.js"></script>
<script src="/static/js/ui.js"></script> <script src="/static/js/ui.js"></script>

View 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 %}