Refactor link header and fix empty page case
This commit is contained in:
parent
ea6f272047
commit
9c3806a175
|
@ -7,11 +7,19 @@ from django.http import HttpRequest
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class PaginationResult:
|
class PaginationResult:
|
||||||
|
"""
|
||||||
|
Represents a pagination result for Mastodon (it does Link header stuff)
|
||||||
|
"""
|
||||||
|
|
||||||
#: A list of objects that matched the pagination query.
|
#: A list of objects that matched the pagination query.
|
||||||
results: list[models.Model]
|
results: list[models.Model]
|
||||||
|
|
||||||
#: The actual applied limit, which may be different from what was requested.
|
#: The actual applied limit, which may be different from what was requested.
|
||||||
limit: int
|
limit: int
|
||||||
sort_attribute: str
|
|
||||||
|
@classmethod
|
||||||
|
def empty(cls):
|
||||||
|
return cls(results=[], limit=20)
|
||||||
|
|
||||||
def next(self, request: HttpRequest, allowed_params: list[str]):
|
def next(self, request: HttpRequest, allowed_params: list[str]):
|
||||||
"""
|
"""
|
||||||
|
@ -37,6 +45,17 @@ class PaginationResult:
|
||||||
|
|
||||||
return f"{request.build_absolute_uri(request.path)}?{urllib.parse.urlencode(params)}"
|
return f"{request.build_absolute_uri(request.path)}?{urllib.parse.urlencode(params)}"
|
||||||
|
|
||||||
|
def link_header(self, request: HttpRequest, allowed_params: list[str]):
|
||||||
|
"""
|
||||||
|
Creates a link header for the given request
|
||||||
|
"""
|
||||||
|
return ", ".join(
|
||||||
|
(
|
||||||
|
f'<{self.next(request, allowed_params)}>; rel="next"',
|
||||||
|
f'<{self.prev(request, allowed_params)}>; rel="prev"',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_params(request: HttpRequest, allowed_params: list[str]):
|
def filter_params(request: HttpRequest, allowed_params: list[str]):
|
||||||
params = {}
|
params = {}
|
||||||
|
@ -71,12 +90,12 @@ class MastodonPaginator:
|
||||||
max_id: str | None,
|
max_id: str | None,
|
||||||
since_id: str | None,
|
since_id: str | None,
|
||||||
limit: int | None,
|
limit: int | None,
|
||||||
):
|
) -> PaginationResult:
|
||||||
if max_id:
|
if max_id:
|
||||||
try:
|
try:
|
||||||
anchor = self.anchor_model.objects.get(pk=max_id)
|
anchor = self.anchor_model.objects.get(pk=max_id)
|
||||||
except self.anchor_model.DoesNotExist:
|
except self.anchor_model.DoesNotExist:
|
||||||
return []
|
return PaginationResult.empty()
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
**{self.sort_attribute + "__lt": getattr(anchor, self.sort_attribute)}
|
**{self.sort_attribute + "__lt": getattr(anchor, self.sort_attribute)}
|
||||||
)
|
)
|
||||||
|
@ -85,7 +104,7 @@ class MastodonPaginator:
|
||||||
try:
|
try:
|
||||||
anchor = self.anchor_model.objects.get(pk=since_id)
|
anchor = self.anchor_model.objects.get(pk=since_id)
|
||||||
except self.anchor_model.DoesNotExist:
|
except self.anchor_model.DoesNotExist:
|
||||||
return []
|
return PaginationResult.empty()
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
**{self.sort_attribute + "__gt": getattr(anchor, self.sort_attribute)}
|
**{self.sort_attribute + "__gt": getattr(anchor, self.sort_attribute)}
|
||||||
)
|
)
|
||||||
|
@ -96,7 +115,7 @@ class MastodonPaginator:
|
||||||
try:
|
try:
|
||||||
anchor = self.anchor_model.objects.get(pk=min_id)
|
anchor = self.anchor_model.objects.get(pk=min_id)
|
||||||
except self.anchor_model.DoesNotExist:
|
except self.anchor_model.DoesNotExist:
|
||||||
return []
|
return PaginationResult.empty()
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
**{self.sort_attribute + "__gt": getattr(anchor, self.sort_attribute)}
|
**{self.sort_attribute + "__gt": getattr(anchor, self.sort_attribute)}
|
||||||
).order_by(self.sort_attribute)
|
).order_by(self.sort_attribute)
|
||||||
|
@ -107,5 +126,4 @@ class MastodonPaginator:
|
||||||
return PaginationResult(
|
return PaginationResult(
|
||||||
results=list(queryset[:limit]),
|
results=list(queryset[:limit]),
|
||||||
limit=limit,
|
limit=limit,
|
||||||
sort_attribute=self.sort_attribute,
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -132,7 +132,9 @@ def account_statuses(
|
||||||
)
|
)
|
||||||
|
|
||||||
if pager.results:
|
if pager.results:
|
||||||
params = [
|
response.headers["Link"] = pager.link_header(
|
||||||
|
request,
|
||||||
|
[
|
||||||
"limit",
|
"limit",
|
||||||
"id",
|
"id",
|
||||||
"exclude_reblogs",
|
"exclude_reblogs",
|
||||||
|
@ -140,12 +142,7 @@ def account_statuses(
|
||||||
"only_media",
|
"only_media",
|
||||||
"pinned",
|
"pinned",
|
||||||
"tagged",
|
"tagged",
|
||||||
]
|
],
|
||||||
response.headers["Link"] = ", ".join(
|
|
||||||
(
|
|
||||||
f'<{pager.next(request, params)}>; rel="next"',
|
|
||||||
f'<{pager.prev(request, params)}>; rel="prev"',
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
interactions = PostInteraction.get_post_interactions(
|
interactions = PostInteraction.get_post_interactions(
|
||||||
|
|
|
@ -45,13 +45,7 @@ def notifications(
|
||||||
)
|
)
|
||||||
|
|
||||||
if pager.results:
|
if pager.results:
|
||||||
params = ["limit", "account_id"]
|
response.headers["Link"] = pager.link_header(request, ["limit", "account_id"])
|
||||||
response.headers["Link"] = ", ".join(
|
|
||||||
(
|
|
||||||
f'<{pager.next(request, params)}>; rel="next"',
|
|
||||||
f'<{pager.prev(request, params)}>; rel="prev"',
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
interactions = PostInteraction.get_event_interactions(
|
interactions = PostInteraction.get_event_interactions(
|
||||||
pager.results, request.identity
|
pager.results, request.identity
|
||||||
|
|
|
@ -33,12 +33,7 @@ def home(
|
||||||
)
|
)
|
||||||
|
|
||||||
if pager.results:
|
if pager.results:
|
||||||
response.headers["Link"] = ", ".join(
|
response.headers["Link"] = pager.link_header(request, ["limit"])
|
||||||
(
|
|
||||||
f"<{pager.next(request, ['limit'])}>; rel=\"next\"",
|
|
||||||
f"<{pager.prev(request, ['limit'])}>; rel=\"prev\"",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
event.to_mastodon_status_json(interactions=interactions)
|
event.to_mastodon_status_json(interactions=interactions)
|
||||||
|
@ -79,12 +74,9 @@ def public(
|
||||||
)
|
)
|
||||||
|
|
||||||
if pager.results:
|
if pager.results:
|
||||||
params = ["limit", "local", "remote", "only_media"]
|
response.headers["Link"] = pager.link_header(
|
||||||
response.headers["Link"] = ", ".join(
|
request,
|
||||||
(
|
["limit", "local", "remote", "only_media"],
|
||||||
f'<{pager.next(request, params)}>; rel="next"',
|
|
||||||
f'<{pager.prev(request, params)}>; rel="prev"',
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
interactions = PostInteraction.get_post_interactions(
|
interactions = PostInteraction.get_post_interactions(
|
||||||
|
@ -123,12 +115,9 @@ def hashtag(
|
||||||
)
|
)
|
||||||
|
|
||||||
if pager.results:
|
if pager.results:
|
||||||
params = ["limit", "local", "hashtag", "only_media"]
|
response.headers["Link"] = pager.link_header(
|
||||||
response.headers["Link"] = ", ".join(
|
request,
|
||||||
(
|
["limit", "local", "remote", "only_media"],
|
||||||
f'<{pager.next(request, params)}>; rel="next"',
|
|
||||||
f'<{pager.prev(request, params)}>; rel="prev"',
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
interactions = PostInteraction.get_post_interactions(
|
interactions = PostInteraction.get_post_interactions(
|
||||||
|
|
Loading…
Reference in New Issue