Move timelines to a service class

This commit is contained in:
Andrew Godwin 2022-12-21 19:47:48 +00:00
parent bf5a46df38
commit e2371a3cd7
5 changed files with 108 additions and 109 deletions

View File

@ -1,2 +1,3 @@
from .post import PostService # noqa
from .search import SearchService # noqa
from .timeline import TimelineService # noqa

View File

@ -0,0 +1,89 @@
from django.db import models
from activities.models import Hashtag, Post, TimelineEvent
from users.models import Identity
class TimelineService:
"""
Timelines and stuff!
"""
def __init__(self, identity: Identity):
self.identity = identity
def home(self) -> models.QuerySet[TimelineEvent]:
return (
TimelineEvent.objects.filter(
identity=self.identity,
type__in=[TimelineEvent.Types.post, TimelineEvent.Types.boost],
)
.select_related(
"subject_post",
"subject_post__author",
"subject_post__author__domain",
"subject_identity",
"subject_identity__domain",
"subject_post_interaction",
"subject_post_interaction__identity",
"subject_post_interaction__identity__domain",
)
.prefetch_related(
"subject_post__attachments",
"subject_post__mentions",
"subject_post__emojis",
)
.order_by("-published")
)
def local(self) -> models.QuerySet[Post]:
return (
Post.objects.local_public()
.not_hidden()
.filter(author__restriction=Identity.Restriction.none)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions", "emojis")
.order_by("-published")
)
def federated(self) -> models.QuerySet[Post]:
return (
Post.objects.public()
.not_hidden()
.filter(author__restriction=Identity.Restriction.none)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions", "emojis")
.order_by("-published")
)
def hashtag(self, hashtag: str | Hashtag) -> models.QuerySet[Post]:
return (
Post.objects.public()
.not_hidden()
.filter(author__restriction=Identity.Restriction.none)
.tagged_with(hashtag)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions")
.order_by("-published")
)
def notifications(self, types: list[str]) -> models.QuerySet[TimelineEvent]:
return (
TimelineEvent.objects.filter(identity=self.identity, type__in=types)
.order_by("-published")
.select_related(
"subject_post",
"subject_post__author",
"subject_post__author__domain",
"subject_identity",
"subject_identity__domain",
"subject_post_interaction",
"subject_post_interaction__identity",
"subject_post_interaction__identity__domain",
)
.prefetch_related(
"subject_post__emojis",
"subject_post__mentions",
"subject_post__attachments",
)
)

View File

@ -3,10 +3,10 @@ from django.shortcuts import get_object_or_404, redirect
from django.utils.decorators import method_decorator
from django.views.generic import ListView, TemplateView
from activities.models import Hashtag, Post, PostInteraction, TimelineEvent
from activities.models import Hashtag, PostInteraction, TimelineEvent
from activities.services import TimelineService
from core.decorators import cache_page
from users.decorators import identity_required
from users.models import Identity
from .compose import Compose
@ -22,28 +22,7 @@ class Home(TemplateView):
return self.form_class(request=self.request, **self.get_form_kwargs())
def get_context_data(self):
events = (
TimelineEvent.objects.filter(
identity=self.request.identity,
type__in=[TimelineEvent.Types.post, TimelineEvent.Types.boost],
)
.select_related(
"subject_post",
"subject_post__author",
"subject_post__author__domain",
"subject_identity",
"subject_identity__domain",
"subject_post_interaction",
"subject_post_interaction__identity",
"subject_post_interaction__identity__domain",
)
.prefetch_related(
"subject_post__attachments",
"subject_post__mentions",
"subject_post__emojis",
)
.order_by("-published")
)
events = TimelineService(self.request.identity).home()
paginator = Paginator(events, 50)
page_number = self.request.GET.get("page")
context = {
@ -80,14 +59,7 @@ class Tag(ListView):
return super().get(request, *args, **kwargs)
def get_queryset(self):
return (
Post.objects.public()
.filter(author__restriction=Identity.Restriction.none)
.tagged_with(self.hashtag)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions")
.order_by("-published")
)
return TimelineService(self.request.identity).hashtag(self.hashtag)
def get_context_data(self):
context = super().get_context_data()
@ -111,13 +83,7 @@ class Local(ListView):
paginate_by = 50
def get_queryset(self):
return (
Post.objects.local_public()
.filter(author__restriction=Identity.Restriction.none)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions", "emojis")
.order_by("-published")
)
return TimelineService(self.request.identity).local()
def get_context_data(self):
context = super().get_context_data()
@ -138,15 +104,7 @@ class Federated(ListView):
paginate_by = 50
def get_queryset(self):
return (
Post.objects.filter(
visibility=Post.Visibilities.public, in_reply_to__isnull=True
)
.filter(author__restriction=Identity.Restriction.none)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions", "emojis")
.order_by("-published")
)
return TimelineService(self.request.identity).federated()
def get_context_data(self):
context = super().get_context_data()
@ -187,25 +145,7 @@ class Notifications(ListView):
for type_name, type in self.notification_types.items():
if notification_options.get(type_name, True):
types.append(type)
return (
TimelineEvent.objects.filter(identity=self.request.identity, type__in=types)
.order_by("-published")
.select_related(
"subject_post",
"subject_post__author",
"subject_post__author__domain",
"subject_identity",
"subject_identity__domain",
"subject_post_interaction",
"subject_post_interaction__identity",
"subject_post_interaction__identity__domain",
)
.prefetch_related(
"subject_post__emojis",
"subject_post__mentions",
"subject_post__attachments",
)
)
return TimelineService(self.request.identity).notifications(types)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

View File

@ -1,4 +1,5 @@
from activities.models import PostInteraction, TimelineEvent
from activities.services import TimelineService
from api import schemas
from api.decorators import identity_required
from api.pagination import MastodonPaginator
@ -28,13 +29,8 @@ def notifications(
requested_types = set(base_types.keys())
requested_types.difference_update(excluded_types)
# Use that to pull relevant events
queryset = (
TimelineEvent.objects.filter(
identity=request.identity,
type__in=[base_types[r] for r in requested_types],
)
.order_by("-published")
.select_related("subject_post", "subject_post__author", "subject_identity")
queryset = TimelineService(request.identity).notifications(
[base_types[r] for r in requested_types]
)
paginator = MastodonPaginator(TimelineEvent)
events = paginator.paginate(

View File

@ -1,9 +1,9 @@
from activities.models import Post, PostInteraction, TimelineEvent
from activities.models import Post, PostInteraction
from activities.services import TimelineService
from api import schemas
from api.decorators import identity_required
from api.pagination import MastodonPaginator
from api.views.base import api_router
from users.models import Identity
@api_router.get("/v1/timelines/home", response=list[schemas.Status])
@ -16,22 +16,7 @@ def home(
limit: int = 20,
):
paginator = MastodonPaginator(Post)
queryset = (
TimelineEvent.objects.filter(
identity=request.identity,
type__in=[TimelineEvent.Types.post],
)
.select_related(
"subject_post",
"subject_post__author",
"subject_post__author__domain",
)
.prefetch_related(
"subject_post__attachments",
"subject_post__mentions",
)
.order_by("-published")
)
queryset = TimelineService(request.identity).home()
events = paginator.paginate(
queryset,
min_id=min_id,
@ -58,16 +43,11 @@ def public(
min_id: str | None = None,
limit: int = 20,
):
queryset = (
Post.objects.public()
.filter(author__restriction=Identity.Restriction.none)
.select_related("author")
.prefetch_related("attachments")
.order_by("-published")
)
if local:
queryset = queryset.filter(local=True)
elif remote:
queryset = TimelineService(request.identity).local()
else:
queryset = TimelineService(request.identity).federated()
if remote:
queryset = queryset.filter(local=False)
if only_media:
queryset = queryset.filter(attachments__id__isnull=True)
@ -97,14 +77,7 @@ def hashtag(
):
if limit > 40:
limit = 40
queryset = (
Post.objects.public()
.filter(author__restriction=Identity.Restriction.none)
.tagged_with(hashtag)
.select_related("author")
.prefetch_related("attachments")
.order_by("-published")
)
queryset = TimelineService(request.identity).hashtag(hashtag)
if local:
queryset = queryset.filter(local=True)
if only_media: