From 7276b15e395e4b84ff05e3e48741b3edb995afb6 Mon Sep 17 00:00:00 2001 From: Deimos Date: Fri, 3 Aug 2018 00:23:14 -0600 Subject: [PATCH] Add paginated topics/comments pages to own profile This needs some more work still to clean up a few things, but it should be good enough for now. This allows users to see (only on their own user page), separate "tabs" for Topics and Comments, and those separate listings are paginated. --- tildes/tildes/__init__.py | 7 +- tildes/tildes/models/comment/comment_query.py | 4 +- .../tildes/templates/macros/user_menu.jinja2 | 2 +- tildes/tildes/templates/user.jinja2 | 42 +++++++++++- tildes/tildes/views/user.py | 66 +++++++++++++++++-- 5 files changed, 105 insertions(+), 16 deletions(-) diff --git a/tildes/tildes/__init__.py b/tildes/tildes/__init__.py index 02df50d..655aee9 100644 --- a/tildes/tildes/__init__.py +++ b/tildes/tildes/__init__.py @@ -137,10 +137,11 @@ def current_listing_base_url( The `query` argument allows adding query variables to the generated url. """ - if request.matched_route.name not in ('home', 'group'): + if request.matched_route.name not in ('home', 'group', 'user'): raise AttributeError('Current route is not supported.') - base_view_vars = ('order', 'period', 'per_page', 'tag', 'unfiltered') + base_view_vars = ( + 'order', 'period', 'per_page', 'tag', 'type', 'unfiltered') query_vars = { key: val for key, val in request.GET.copy().items() if key in base_view_vars @@ -165,7 +166,7 @@ def current_listing_normal_url( The `query` argument allows adding query variables to the generated url. """ - if request.matched_route.name not in ('home', 'group'): + if request.matched_route.name not in ('home', 'group', 'user'): raise AttributeError('Current route is not supported.') normal_view_vars = ('order', 'period', 'per_page') diff --git a/tildes/tildes/models/comment/comment_query.py b/tildes/tildes/models/comment/comment_query.py index 672367b..fb029f8 100644 --- a/tildes/tildes/models/comment/comment_query.py +++ b/tildes/tildes/models/comment/comment_query.py @@ -4,12 +4,12 @@ from typing import Any from pyramid.request import Request -from tildes.models import ModelQuery +from tildes.models.pagination import PaginatedQuery from .comment import Comment from .comment_vote import CommentVote -class CommentQuery(ModelQuery): +class CommentQuery(PaginatedQuery): """Specialized ModelQuery for Comments.""" def __init__(self, request: Request) -> None: diff --git a/tildes/tildes/templates/macros/user_menu.jinja2 b/tildes/tildes/templates/macros/user_menu.jinja2 index 761a85a..0033ab9 100644 --- a/tildes/tildes/templates/macros/user_menu.jinja2 +++ b/tildes/tildes/templates/macros/user_menu.jinja2 @@ -7,7 +7,7 @@ diff --git a/tildes/tildes/templates/user.jinja2 b/tildes/tildes/templates/user.jinja2 index 1e3a1f1..a043528 100644 --- a/tildes/tildes/templates/user.jinja2 +++ b/tildes/tildes/templates/user.jinja2 @@ -10,13 +10,33 @@ {{ user.username }} {% endblock %} -{% block main_heading %}{{ user.username }}'s recent activity{% endblock %} +{# Only show the heading if they can't see the type tabs #} +{% block main_heading %} + {% if not request.has_permission('view_types', user) %} + {{ user.username }}'s recent activity + {% endif %} +{% endblock %} {% block content %} +{% if request.has_permission('view_types', user) %} +
+ +
  • + Recent activity +
  • +
  • + Topics +
  • +
  • + Comments +
  • +
    +
    +{% endif %} -{% if merged_posts %} +{% if posts %}
      - {% for post in merged_posts if request.has_permission('view', post) %} + {% for post in posts if request.has_permission('view', post) %}
    1. {% if post is topic %} {{ render_topic_for_listing(post, show_group=True) }} @@ -27,6 +47,22 @@
    2. {% endfor %}
    + + {% if post_type and (posts.has_prev_page or posts.has_next_page) %} + + {% endif %} {% else %}

    This user hasn't made any posts

    diff --git a/tildes/tildes/views/user.py b/tildes/tildes/views/user.py index f5ced8a..c7da379 100644 --- a/tildes/tildes/views/user.py +++ b/tildes/tildes/views/user.py @@ -1,19 +1,24 @@ """Views related to a specific user.""" +from typing import List, Union + +from marshmallow.fields import String +from marshmallow.validate import OneOf from pyramid.request import Request from pyramid.view import view_config from sqlalchemy.sql.expression import desc +from webargs.pyramidparser import use_kwargs from tildes.models.comment import Comment from tildes.models.topic import Topic -from tildes.models.user import UserInviteCode - +from tildes.models.user import User, UserInviteCode +from tildes.schemas.topic_listing import TopicListingSchema -@view_config(route_name='user', renderer='user.jinja2') -def get_user(request: Request) -> dict: - """Generate the main user info page.""" - user = request.context +def _get_user_recent_activity( + request: Request, + user: User, +) -> List[Union[Comment, Topic]]: page_size = 20 # Since we don't know how many comments or topics will be needed to make @@ -54,9 +59,56 @@ def get_user(request: Request) -> dict: ) merged_posts = merged_posts[:page_size] + return merged_posts + + +@view_config(route_name='user', renderer='user.jinja2') +@use_kwargs(TopicListingSchema(only=('after', 'before', 'per_page'))) +@use_kwargs({ + 'post_type': String( + load_from='type', + validate=OneOf(('topic', 'comment')), + ), +}) +def get_user( + request: Request, + after: str, + before: str, + per_page: int, + post_type: str = None, +) -> dict: + """Generate the main user history page.""" + user = request.context + + if not request.has_permission('view_types', user): + post_type = None + + if post_type: + if post_type == 'topic': + query = request.query(Topic).filter(Topic.user == user) + elif post_type == 'comment': + query = request.query(Comment).filter(Comment.user == user) + + if before: + query = query.before_id36(before) + + if after: + query = query.after_id36(after) + + query = query.join_all_relationships() + + # include removed posts if the user's looking at their own page + if user == request.user: + query = query.include_removed() + + posts = query.get_page(per_page) + else: + posts = _get_user_recent_activity(request, user) + return { 'user': user, - 'merged_posts': merged_posts, + 'posts': posts, + 'post_type': post_type, }