diff --git a/app/models.py b/app/models.py index 0e98d06..f7bda98 100644 --- a/app/models.py +++ b/app/models.py @@ -50,6 +50,10 @@ class Users(Model): WHERE users.id = ?""" return db.fetch_one(q, self.id) + def get_posts(self, per_page: int, page: int) -> list: + q = f'{Posts.FULL_POSTS_QUERY} WHERE posts.user_id = ? ORDER BY posts.created_at DESC LIMIT ? OFFSET ?' + return db.query(q, self.id, per_page, (page - 1) * per_page) + def get_all_subscriptions(self): q = """ SELECT threads.title AS thread_title, threads.slug AS thread_slug diff --git a/app/routes/users.py b/app/routes/users.py index 54dc574..29a3af4 100644 --- a/app/routes/users.py +++ b/app/routes/users.py @@ -1,4 +1,4 @@ -from flask import Blueprint, redirect, url_for, render_template, request, session +from flask import Blueprint, redirect, url_for, render_template, request, session, abort from functools import wraps import time @@ -7,9 +7,10 @@ from ..auth import ( is_logged_in, parse_username, is_password_valid, login_required ) -from ..models import Users +from ..models import Users, Posts, Reactions from ..constants import PermissionLevel from secrets import compare_digest as compare_timesafe +import math bp = Blueprint('users', __name__, url_prefix='/users/') @@ -104,6 +105,7 @@ def sign_up_post(): @bp.get('//') def user_page(username): + username = username.lower() target_user = Users.find({'username': username}) if not target_user: abort(404) @@ -111,25 +113,51 @@ def user_page(username): @bp.get('//posts/') def posts(username): - return 'stub' + username = username.lower() + if username == 'deleteduser': + abort(404) + target_user = Users.find({'username': username}) + PER_PAGE = 10 + posts_count = Posts.count({'user_id': target_user.id}) + page_count = max(1, math.ceil(posts_count / PER_PAGE)) + page = 1 + try: + page = max(1, min(int(request.args.get('page', default=1)), page_count)) + except ValueError: + abort(404) + posts = target_user.get_posts(PER_PAGE, page) + return render_template( + 'users/posts.html', posts=posts, + page=page, page_count=page_count, + target_user=target_user, Reactions=Reactions + ) @bp.get('//threads/') def threads(username): + username = username.lower() + if username == 'deleteduser': + abort(404) return 'stub' @bp.get('//comments/') def comments(username): + username = username.lower() + if username == 'deleteduser': + abort(404) return 'stub' @bp.get('//settings/') def settings(username): + username = username.lower() return 'stub' @bp.get('//inbox/') def inbox(username): + username = username.lower() return 'stub' @bp.get('//bookmarks/') def bookmarks(username): + username = username.lower() return 'stub' diff --git a/app/templates/common/macros.html b/app/templates/common/macros.html index 217b181..612578e 100644 --- a/app/templates/common/macros.html +++ b/app/templates/common/macros.html @@ -1,7 +1,6 @@ {%- from 'common/icons.html' import icn_info, icn_warn, icn_error, icn_bookmark -%} {% macro timestamp(unix_ts) -%} -{#{{ unix_ts | ts_datetime('%Y-%m-%d %H:%M')}} ST#} {{ unix_ts | ts_datetime('%Y-%m-%d %H:%M')}} ST {%- endmacro %} @@ -114,7 +113,7 @@ {% macro full_post( post, render_sig=true, is_latest=false, show_toolbar=true, is_editing=false, thread=none, - show_reactions=true + show_reactions=true, show_thread=false ) -%} {%- if is_logged_in() -%} {%- set can_delete = post.user_id == get_active_user().id or is_mod() -%} @@ -143,13 +142,18 @@
- - {%- if post.edited_at <= post.created_at -%} - Posted on {{timestamp(post.created_at)}} - {%- else -%} - Edited on {{timestamp(post.edited_at)}} + + + {%- if post.edited_at <= post.created_at -%} + Posted on {{timestamp(post.created_at)}} + {%- else -%} + Edited on {{timestamp(post.edited_at)}} + {%- endif -%} + + {%- if show_thread -%} + in thread {{post.thread_title}} {%- endif -%} - + {%- if show_toolbar -%} {%- if owns -%} diff --git a/app/templates/users/log_in.html b/app/templates/users/log_in.html index 511daae..2f6c159 100644 --- a/app/templates/users/log_in.html +++ b/app/templates/users/log_in.html @@ -1,3 +1,4 @@ +{% from 'common/macros.html' import infobox with context %} {% from 'common/macros.html' import subheader %} {%- extends 'base.html' -%} {%- block title -%}log in{%- endblock -%} @@ -7,9 +8,7 @@ Welcome back! No account yet? Sign up {%- endset -%} {{ subheader('Log in', welcome)}} {%- if request.args.get('error') -%} -
- {{request.args.get('error')}} -
+ {{infobox(request.args.error, InfoboxKind.ERROR)}} {%- endif -%}
diff --git a/app/templates/users/posts.html b/app/templates/users/posts.html new file mode 100644 index 0000000..9c874c1 --- /dev/null +++ b/app/templates/users/posts.html @@ -0,0 +1,30 @@ +{%- from 'common/macros.html' import full_post with context -%} +{%- from 'common/macros.html' import subheader, pager -%} +{%- extends 'base.html' -%} +{%- block title -%}{{ target_user.get_readable_name() }}'s posts{%- endblock -%} +{%- block content -%} +{%- set td -%} + Back to profile + {%- if posts -%} +
+ Page + {{- pager(page, page_count) -}} +
+ {%- endif -%} +{%- endset -%} +{%- call() subheader("%s's posts" % target_user.get_readable_name(), td) -%} +{%- endcall -%} +{%- if posts -%} +{%- for post in posts -%} +
{{full_post(post, show_toolbar=false, show_thread=true)}}
+{%- endfor -%} +
+
+ Page + {{- pager(page, page_count) -}} +
+
+{%- else -%} +
{{target_user.get_readable_name()}} has no posts.
+{%- endif -%} +{%- endblock -%} diff --git a/app/templates/users/sign_up.html b/app/templates/users/sign_up.html index 14e0aa8..bb92381 100644 --- a/app/templates/users/sign_up.html +++ b/app/templates/users/sign_up.html @@ -1,3 +1,4 @@ +{% from 'common/macros.html' import infobox with context %} {% from 'common/macros.html' import subheader %} {%- extends 'base.html' -%} {%- block title -%}sign up{%- endblock -%} @@ -7,9 +8,7 @@ Please read the rules etc. stub {%- endset -%} {{ subheader('Sign up', welcome)}} {%- if request.args.get('error') -%} -
- {{request.args.get('error')}} -
+ {{infobox(request.args.error, InfoboxKind.ERROR)}} {%- endif -%}