Browse Source

Merge branch 'master' into clear_all_notifications

merge-requests/20/head
James Southern 7 years ago
parent
commit
5b6184181e
  1. 4
      tildes/scss/_base.scss
  2. 7
      tildes/tildes/__init__.py
  3. 4
      tildes/tildes/models/comment/comment_query.py
  4. 26
      tildes/tildes/models/pagination.py
  5. 2
      tildes/tildes/templates/macros/user_menu.jinja2
  6. 4
      tildes/tildes/templates/topic_listing.jinja2
  7. 42
      tildes/tildes/templates/user.jinja2
  8. 66
      tildes/tildes/views/user.py

4
tildes/scss/_base.scss

@ -161,6 +161,10 @@ ol {
margin-top: 0.2rem;
max-width: $paragraph-max-width - 2rem;
}
&:last-child {
margin-bottom: 0.2rem;
}
}
p {

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.
"""
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')

4
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:

26
tildes/tildes/models/pagination.py

@ -3,9 +3,9 @@
from typing import Any, Iterator, List, Optional, TypeVar
from pyramid.request import Request
from sqlalchemy import Column, func
from sqlalchemy import Column, func, inspect
from tildes.lib.id import id36_to_id
from tildes.lib.id import id_to_id36, id36_to_id
from .model_query import ModelQuery
@ -22,7 +22,8 @@ class PaginatedQuery(ModelQuery):
super().__init__(model_cls, request)
self._sort_column: Optional[Column] = None
# default to sorting by created_time descending (newest first)
self._sort_column = model_cls.created_time
self.sort_desc = True
self.after_id: Optional[int] = None
@ -135,7 +136,6 @@ class PaginatedQuery(ModelQuery):
"""Finalize the query before execution."""
query = super()._finalize()
if self._sort_column:
# if the query is reversed, we need to sort in the opposite dir
# (basically self.sort_desc XOR self.is_reversed)
desc = self.sort_desc
@ -204,3 +204,21 @@ class PaginatedResults:
def __len__(self) -> int:
"""Return the number of results."""
return len(self.results)
@property
def next_page_after_id36(self) -> str:
"""Return "after" ID36 that should be used to fetch the next page."""
if not self.has_next_page:
raise AttributeError
next_id = inspect(self.results[-1]).identity[0]
return id_to_id36(next_id)
@property
def prev_page_before_id36(self) -> str:
"""Return "before" ID36 that should be used to fetch the prev page."""
if not self.has_prev_page:
raise AttributeError
prev_id = inspect(self.results[0]).identity[0]
return id_to_id36(prev_id)

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

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

4
tildes/tildes/templates/topic_listing.jinja2

@ -154,13 +154,13 @@
<div class="pagination">
{% if topics.has_prev_page %}
<a class="page-item btn" id="prev-page"
href="{{ request.current_listing_base_url({'before': topics[0].topic_id36}) }}"
href="{{ request.current_listing_base_url({'before': topics.prev_page_before_id36}) }}"
>Prev</a>
{% endif %}
{% if topics.has_next_page %}
<a class="page-item btn" id="next-page"
href="{{ request.current_listing_base_url({'after': topics[-1].topic_id36}) }}"
href="{{ request.current_listing_base_url({'after': topics.next_page_after_id36}) }}"
>Next</a>
{% endif %}
</div>

42
tildes/tildes/templates/user.jinja2

@ -10,13 +10,33 @@
<a class="site-header-context" href="/user/{{ user.username }}">{{ user.username }}</a>
{% 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) %}
<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">
{% for post in merged_posts if request.has_permission('view', post) %}
{% for post in posts if request.has_permission('view', post) %}
<li>
{% if post is topic %}
{{ render_topic_for_listing(post, show_group=True) }}
@ -27,6 +47,22 @@
</li>
{% endfor %}
</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_id36}) }}"
>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_id36}) }}"
>Next</a>
{% endif %}
</div>
{% endif %}
{% else %}
<div class="empty">
<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."""
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,
}

Loading…
Cancel
Save