Fix mastodon pagination to use returned IDs
This commit is contained in:
parent
68e764a36e
commit
252737f846
|
@ -1,5 +1,7 @@
|
|||
import dataclasses
|
||||
import urllib.parse
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
from django.db import models
|
||||
from django.http import HttpRequest
|
||||
|
@ -19,6 +21,9 @@ class PaginationResult:
|
|||
#: The actual applied limit, which may be different from what was requested.
|
||||
limit: int
|
||||
|
||||
#: A list of transformed JSON objects
|
||||
json_results: list[dict] | None = None
|
||||
|
||||
@classmethod
|
||||
def empty(cls):
|
||||
return cls(results=[], limit=20)
|
||||
|
@ -29,9 +34,10 @@ class PaginationResult:
|
|||
"""
|
||||
if not self.results:
|
||||
return None
|
||||
|
||||
if self.json_results is None:
|
||||
raise ValueError("You must JSONify the results first")
|
||||
params = self.filter_params(request, allowed_params)
|
||||
params["max_id"] = self.results[-1].pk
|
||||
params["max_id"] = self.json_results[-1]["id"]
|
||||
|
||||
return f"{request.build_absolute_uri(request.path)}?{urllib.parse.urlencode(params)}"
|
||||
|
||||
|
@ -41,9 +47,10 @@ class PaginationResult:
|
|||
"""
|
||||
if not self.results:
|
||||
return None
|
||||
|
||||
if self.json_results is None:
|
||||
raise ValueError("You must JSONify the results first")
|
||||
params = self.filter_params(request, allowed_params)
|
||||
params["min_id"] = self.results[0].pk
|
||||
params["min_id"] = self.json_results[0]["id"]
|
||||
|
||||
return f"{request.build_absolute_uri(request.path)}?{urllib.parse.urlencode(params)}"
|
||||
|
||||
|
@ -58,6 +65,45 @@ class PaginationResult:
|
|||
)
|
||||
)
|
||||
|
||||
def jsonify_results(self, map_function: Callable[[Any], Any]):
|
||||
"""
|
||||
Replaces our results with ones transformed via map_function
|
||||
"""
|
||||
self.json_results = [map_function(result) for result in self.results]
|
||||
|
||||
def jsonify_posts(self, identity):
|
||||
"""
|
||||
Predefined way of JSON-ifying Post objects
|
||||
"""
|
||||
interactions = PostInteraction.get_post_interactions(self.results, identity)
|
||||
self.jsonify_results(
|
||||
lambda post: post.to_mastodon_json(interactions=interactions)
|
||||
)
|
||||
|
||||
def jsonify_status_events(self, identity):
|
||||
"""
|
||||
Predefined way of JSON-ifying TimelineEvent objects representing statuses
|
||||
"""
|
||||
interactions = PostInteraction.get_event_interactions(self.results, identity)
|
||||
self.jsonify_results(
|
||||
lambda event: event.to_mastodon_status_json(interactions=interactions)
|
||||
)
|
||||
|
||||
def jsonify_notification_events(self, identity):
|
||||
"""
|
||||
Predefined way of JSON-ifying TimelineEvent objects representing notifications
|
||||
"""
|
||||
interactions = PostInteraction.get_event_interactions(self.results, identity)
|
||||
self.jsonify_results(
|
||||
lambda event: event.to_mastodon_notification_json(interactions=interactions)
|
||||
)
|
||||
|
||||
def jsonify_identities(self):
|
||||
"""
|
||||
Predefined way of JSON-ifying Identity objects
|
||||
"""
|
||||
self.jsonify_results(lambda identity: identity.to_mastodon_json())
|
||||
|
||||
@staticmethod
|
||||
def filter_params(request: HttpRequest, allowed_params: list[str]):
|
||||
params = {}
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.http import HttpRequest, HttpResponse, JsonResponse
|
|||
from django.shortcuts import get_object_or_404
|
||||
from ninja import Field
|
||||
|
||||
from activities.models import Post, PostInteraction
|
||||
from activities.models import Post
|
||||
from activities.services import SearchService
|
||||
from api import schemas
|
||||
from api.decorators import identity_required
|
||||
|
@ -143,7 +143,7 @@ def account_statuses(
|
|||
queryset = queryset.filter(attachments__pk__isnull=False)
|
||||
if tagged:
|
||||
queryset = queryset.tagged_with(tagged)
|
||||
|
||||
# Get user posts with pagination
|
||||
paginator = MastodonPaginator(Post, sort_attribute="published")
|
||||
pager = paginator.paginate(
|
||||
queryset,
|
||||
|
@ -152,7 +152,9 @@ def account_statuses(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
# Convert those to the JSON form
|
||||
pager.jsonify_posts(identity=request.identity)
|
||||
# Add a link header if we need to
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(
|
||||
request,
|
||||
|
@ -166,11 +168,7 @@ def account_statuses(
|
|||
"tagged",
|
||||
],
|
||||
)
|
||||
|
||||
interactions = PostInteraction.get_post_interactions(
|
||||
pager.results, request.identity
|
||||
)
|
||||
return [post.to_mastodon_json(interactions=interactions) for post in pager.results]
|
||||
return pager.json_results
|
||||
|
||||
|
||||
@api_router.post("/v1/accounts/{id}/follow", response=schemas.Relationship)
|
||||
|
@ -222,6 +220,7 @@ def account_following(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
pager.jsonify_identities()
|
||||
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(
|
||||
|
@ -229,4 +228,4 @@ def account_following(
|
|||
["limit"],
|
||||
)
|
||||
|
||||
return [result.to_mastodon_json() for result in pager.results]
|
||||
return pager.json_results
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
from activities.models import PostInteraction, TimelineEvent
|
||||
from activities.models import TimelineEvent
|
||||
from activities.services import TimelineService
|
||||
from api import schemas
|
||||
from api.decorators import identity_required
|
||||
|
@ -43,14 +43,9 @@ def notifications(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
pager.jsonify_notification_events(identity=request.identity)
|
||||
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(request, ["limit", "account_id"])
|
||||
|
||||
interactions = PostInteraction.get_event_interactions(
|
||||
pager.results, request.identity
|
||||
)
|
||||
return [
|
||||
event.to_mastodon_notification_json(interactions=interactions)
|
||||
for event in pager.results
|
||||
]
|
||||
return pager.json_results
|
||||
|
|
|
@ -155,6 +155,7 @@ def favourited_by(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
pager.jsonify_identities()
|
||||
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(
|
||||
|
@ -162,7 +163,7 @@ def favourited_by(
|
|||
["limit"],
|
||||
)
|
||||
|
||||
return [result.identity.to_mastodon_json() for result in pager.results]
|
||||
return pager.json_results
|
||||
|
||||
|
||||
@api_router.post("/v1/statuses/{id}/reblog", response=schemas.Status)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
||||
|
||||
from activities.models import Post, PostInteraction
|
||||
from activities.models import Post
|
||||
from activities.services import TimelineService
|
||||
from api import schemas
|
||||
from api.decorators import identity_required
|
||||
|
@ -19,6 +19,7 @@ def home(
|
|||
min_id: str | None = None,
|
||||
limit: int = 20,
|
||||
):
|
||||
# Grab a paginated result set of instances
|
||||
paginator = MastodonPaginator(Post, sort_attribute="published")
|
||||
queryset = TimelineService(request.identity).home()
|
||||
pager = paginator.paginate(
|
||||
|
@ -28,17 +29,12 @@ def home(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
interactions = PostInteraction.get_event_interactions(
|
||||
pager.results, request.identity
|
||||
)
|
||||
|
||||
# Convert those to the JSON form
|
||||
pager.jsonify_status_events(identity=request.identity)
|
||||
# Add the link header if needed
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(request, ["limit"])
|
||||
|
||||
return [
|
||||
event.to_mastodon_status_json(interactions=interactions)
|
||||
for event in pager.results
|
||||
]
|
||||
return pager.json_results
|
||||
|
||||
|
||||
@api_router.get("/v1/timelines/public", response=list[schemas.Status])
|
||||
|
@ -64,6 +60,7 @@ def public(
|
|||
queryset = queryset.filter(local=False)
|
||||
if only_media:
|
||||
queryset = queryset.filter(attachments__id__isnull=True)
|
||||
# Grab a paginated result set of instances
|
||||
paginator = MastodonPaginator(Post, sort_attribute="published")
|
||||
pager = paginator.paginate(
|
||||
queryset,
|
||||
|
@ -72,17 +69,15 @@ def public(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
# Convert those to the JSON form
|
||||
pager.jsonify_posts(identity=request.identity)
|
||||
# Add the link header if needed
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(
|
||||
request,
|
||||
["limit", "local", "remote", "only_media"],
|
||||
)
|
||||
|
||||
interactions = PostInteraction.get_post_interactions(
|
||||
pager.results, request.identity
|
||||
)
|
||||
return [post.to_mastodon_json(interactions=interactions) for post in pager.results]
|
||||
return pager.json_results
|
||||
|
||||
|
||||
@api_router.get("/v1/timelines/tag/{hashtag}", response=list[schemas.Status])
|
||||
|
@ -105,6 +100,7 @@ def hashtag(
|
|||
queryset = queryset.filter(local=True)
|
||||
if only_media:
|
||||
queryset = queryset.filter(attachments__id__isnull=True)
|
||||
# Grab a paginated result set of instances
|
||||
paginator = MastodonPaginator(Post, sort_attribute="published")
|
||||
pager = paginator.paginate(
|
||||
queryset,
|
||||
|
@ -113,17 +109,15 @@ def hashtag(
|
|||
since_id=since_id,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
# Convert those to the JSON form
|
||||
pager.jsonify_posts(identity=request.identity)
|
||||
# Add a link header if we need to
|
||||
if pager.results:
|
||||
response.headers["Link"] = pager.link_header(
|
||||
request,
|
||||
["limit", "local", "remote", "only_media"],
|
||||
)
|
||||
|
||||
interactions = PostInteraction.get_post_interactions(
|
||||
pager.results, request.identity
|
||||
)
|
||||
return [post.to_mastodon_json(interactions=interactions) for post in pager.results]
|
||||
return pager.json_results
|
||||
|
||||
|
||||
@api_router.get("/v1/conversations", response=list[schemas.Status])
|
||||
|
|
Loading…
Reference in New Issue