Browse Source

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.
merge-requests/22/head
Deimos 6 years ago
parent
commit
7276b15e39
  1. 7
      tildes/tildes/__init__.py
  2. 4
      tildes/tildes/models/comment/comment_query.py
  3. 2
      tildes/tildes/templates/macros/user_menu.jinja2
  4. 42
      tildes/tildes/templates/user.jinja2
  5. 66
      tildes/tildes/views/user.py

7
tildes/tildes/__init__.py

@ -137,10 +137,11 @@ def current_listing_base_url(
The `query` argument allows adding query variables to the generated 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.') 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 = { query_vars = {
key: val for key, val in request.GET.copy().items() key: val for key, val in request.GET.copy().items()
if key in base_view_vars 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. 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.') raise AttributeError('Current route is not supported.')
normal_view_vars = ('order', 'period', 'per_page') normal_view_vars = ('order', 'period', 'per_page')

4
tildes/tildes/models/comment/comment_query.py

@ -4,12 +4,12 @@ from typing import Any
from pyramid.request import Request from pyramid.request import Request
from tildes.models import ModelQuery
from tildes.models.pagination import PaginatedQuery
from .comment import Comment from .comment import Comment
from .comment_vote import CommentVote from .comment_vote import CommentVote
class CommentQuery(ModelQuery):
class CommentQuery(PaginatedQuery):
"""Specialized ModelQuery for Comments.""" """Specialized ModelQuery for Comments."""
def __init__(self, request: Request) -> None: def __init__(self, request: Request) -> None:

2
tildes/tildes/templates/macros/user_menu.jinja2

@ -7,7 +7,7 @@
<ul class="nav"> <ul class="nav">
<li class="nav-item {{ 'active' if route == 'user' else ''}}"> <li class="nav-item {{ 'active' if route == 'user' else ''}}">
<a href="/user/{{ request.user }}"> <a href="/user/{{ request.user }}">
Recent activity
Your posts
</a> </a>
</li> </li>
</ul> </ul>

42
tildes/tildes/templates/user.jinja2

@ -10,13 +10,33 @@
<a class="site-header-context" href="/user/{{ user.username }}">{{ user.username }}</a> <a class="site-header-context" href="/user/{{ user.username }}">{{ user.username }}</a>
{% endblock %} {% 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 %} {% block content %}
{% if request.has_permission('view_types', user) %}
<div class="listing-options">
<menu class="tab tab-listing-order">
<li class="tab-item{{' active' if not post_type else ''}}">
<a href="{{ request.current_listing_normal_url() }}">Recent activity</a>
</li>
<li class="tab-item{{' active' if post_type == 'topic' else ''}}">
<a href="{{ request.current_listing_normal_url({'type': 'topic'}) }}">Topics</a>
</li>
<li class="tab-item{{ ' active' if post_type == 'comment' else ''}}">
<a href="{{ request.current_listing_normal_url({'type': 'comment'}) }}">Comments</a>
</li>
</menu>
</div>
{% endif %}
{% if merged_posts %}
{% if posts %}
<ol class="post-listing"> <ol class="post-listing">
{% for post in merged_posts if request.has_permission('view', post) %}
{% for post in posts if request.has_permission('view', post) %}
<li> <li>
{% if post is topic %} {% if post is topic %}
{{ render_topic_for_listing(post, show_group=True) }} {{ render_topic_for_listing(post, show_group=True) }}
@ -27,6 +47,22 @@
</li> </li>
{% endfor %} {% endfor %}
</ol> </ol>
{% if post_type and (posts.has_prev_page or posts.has_next_page) %}
<div class="pagination">
{% if posts.has_prev_page %}
<a class="page-item btn" id="prev-page"
href="{{ request.current_listing_base_url({'before': posts.prev_page_before_id}) }}"
>Prev</a>
{% endif %}
{% if posts.has_next_page %}
<a class="page-item btn" id="next-page"
href="{{ request.current_listing_base_url({'after': posts.next_page_after_id}) }}"
>Next</a>
{% endif %}
</div>
{% endif %}
{% else %} {% else %}
<div class="empty"> <div class="empty">
<h2 class="empty-title">This user hasn't made any posts</h2> <h2 class="empty-title">This user hasn't made any posts</h2>

66
tildes/tildes/views/user.py

@ -1,19 +1,24 @@
"""Views related to a specific user.""" """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.request import Request
from pyramid.view import view_config from pyramid.view import view_config
from sqlalchemy.sql.expression import desc from sqlalchemy.sql.expression import desc
from webargs.pyramidparser import use_kwargs
from tildes.models.comment import Comment from tildes.models.comment import Comment
from tildes.models.topic import Topic 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 page_size = 20
# Since we don't know how many comments or topics will be needed to make # 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] 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 { return {
'user': user, 'user': user,
'merged_posts': merged_posts,
'posts': posts,
'post_type': post_type,
} }

Loading…
Cancel
Save