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 .post import PostService # noqa
from .search import SearchService # 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.utils.decorators import method_decorator
from django.views.generic import ListView, TemplateView 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 core.decorators import cache_page
from users.decorators import identity_required from users.decorators import identity_required
from users.models import Identity
from .compose import Compose from .compose import Compose
@ -22,28 +22,7 @@ class Home(TemplateView):
return self.form_class(request=self.request, **self.get_form_kwargs()) return self.form_class(request=self.request, **self.get_form_kwargs())
def get_context_data(self): def get_context_data(self):
events = ( events = TimelineService(self.request.identity).home()
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")
)
paginator = Paginator(events, 50) paginator = Paginator(events, 50)
page_number = self.request.GET.get("page") page_number = self.request.GET.get("page")
context = { context = {
@ -80,14 +59,7 @@ class Tag(ListView):
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
return ( return TimelineService(self.request.identity).hashtag(self.hashtag)
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")
)
def get_context_data(self): def get_context_data(self):
context = super().get_context_data() context = super().get_context_data()
@ -111,13 +83,7 @@ class Local(ListView):
paginate_by = 50 paginate_by = 50
def get_queryset(self): def get_queryset(self):
return ( return TimelineService(self.request.identity).local()
Post.objects.local_public()
.filter(author__restriction=Identity.Restriction.none)
.select_related("author", "author__domain")
.prefetch_related("attachments", "mentions", "emojis")
.order_by("-published")
)
def get_context_data(self): def get_context_data(self):
context = super().get_context_data() context = super().get_context_data()
@ -138,15 +104,7 @@ class Federated(ListView):
paginate_by = 50 paginate_by = 50
def get_queryset(self): def get_queryset(self):
return ( return TimelineService(self.request.identity).federated()
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")
)
def get_context_data(self): def get_context_data(self):
context = super().get_context_data() context = super().get_context_data()
@ -187,25 +145,7 @@ class Notifications(ListView):
for type_name, type in self.notification_types.items(): for type_name, type in self.notification_types.items():
if notification_options.get(type_name, True): if notification_options.get(type_name, True):
types.append(type) types.append(type)
return ( return TimelineService(self.request.identity).notifications(types)
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",
)
)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)

View File

@ -1,4 +1,5 @@
from activities.models import PostInteraction, TimelineEvent from activities.models import PostInteraction, TimelineEvent
from activities.services import TimelineService
from api import schemas from api import schemas
from api.decorators import identity_required from api.decorators import identity_required
from api.pagination import MastodonPaginator from api.pagination import MastodonPaginator
@ -28,13 +29,8 @@ def notifications(
requested_types = set(base_types.keys()) requested_types = set(base_types.keys())
requested_types.difference_update(excluded_types) requested_types.difference_update(excluded_types)
# Use that to pull relevant events # Use that to pull relevant events
queryset = ( queryset = TimelineService(request.identity).notifications(
TimelineEvent.objects.filter( [base_types[r] for r in requested_types]
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")
) )
paginator = MastodonPaginator(TimelineEvent) paginator = MastodonPaginator(TimelineEvent)
events = paginator.paginate( 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 import schemas
from api.decorators import identity_required from api.decorators import identity_required
from api.pagination import MastodonPaginator from api.pagination import MastodonPaginator
from api.views.base import api_router from api.views.base import api_router
from users.models import Identity
@api_router.get("/v1/timelines/home", response=list[schemas.Status]) @api_router.get("/v1/timelines/home", response=list[schemas.Status])
@ -16,22 +16,7 @@ def home(
limit: int = 20, limit: int = 20,
): ):
paginator = MastodonPaginator(Post) paginator = MastodonPaginator(Post)
queryset = ( queryset = TimelineService(request.identity).home()
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")
)
events = paginator.paginate( events = paginator.paginate(
queryset, queryset,
min_id=min_id, min_id=min_id,
@ -58,16 +43,11 @@ def public(
min_id: str | None = None, min_id: str | None = None,
limit: int = 20, limit: int = 20,
): ):
queryset = (
Post.objects.public()
.filter(author__restriction=Identity.Restriction.none)
.select_related("author")
.prefetch_related("attachments")
.order_by("-published")
)
if local: if local:
queryset = queryset.filter(local=True) queryset = TimelineService(request.identity).local()
elif remote: else:
queryset = TimelineService(request.identity).federated()
if remote:
queryset = queryset.filter(local=False) queryset = queryset.filter(local=False)
if only_media: if only_media:
queryset = queryset.filter(attachments__id__isnull=True) queryset = queryset.filter(attachments__id__isnull=True)
@ -97,14 +77,7 @@ def hashtag(
): ):
if limit > 40: if limit > 40:
limit = 40 limit = 40
queryset = ( queryset = TimelineService(request.identity).hashtag(hashtag)
Post.objects.public()
.filter(author__restriction=Identity.Restriction.none)
.tagged_with(hashtag)
.select_related("author")
.prefetch_related("attachments")
.order_by("-published")
)
if local: if local:
queryset = queryset.filter(local=True) queryset = queryset.filter(local=True)
if only_media: if only_media: