Prune some unnecessary async usage
This commit is contained in:
parent
31c743319e
commit
0915b17c4b
|
@ -319,23 +319,3 @@ class FanOut(StatorModel):
|
|||
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
||||
### Async helpers ###
|
||||
|
||||
async def afetch_full(self):
|
||||
"""
|
||||
Returns a version of the object with all relations pre-loaded
|
||||
"""
|
||||
return (
|
||||
await FanOut.objects.select_related(
|
||||
"identity",
|
||||
"subject_post",
|
||||
"subject_post_interaction",
|
||||
"subject_identity",
|
||||
"subject_identity__domain",
|
||||
)
|
||||
.prefetch_related(
|
||||
"subject_post__emojis",
|
||||
)
|
||||
.aget(pk=self.pk)
|
||||
)
|
||||
|
|
|
@ -447,18 +447,6 @@ class Post(StatorModel):
|
|||
"replies": self.stats.get("replies", 0) if self.stats else 0,
|
||||
}
|
||||
|
||||
### Async helpers ###
|
||||
|
||||
async def afetch_full(self) -> "Post":
|
||||
"""
|
||||
Returns a version of the object with all relations pre-loaded
|
||||
"""
|
||||
return (
|
||||
await Post.objects.select_related("author", "author__domain")
|
||||
.prefetch_related("mentions", "mentions__domain", "attachments", "emojis")
|
||||
.aget(pk=self.pk)
|
||||
)
|
||||
|
||||
### Local creation/editing ###
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -27,103 +27,89 @@ class PostInteractionStates(StateGraph):
|
|||
return [cls.new, cls.fanned_out]
|
||||
|
||||
@classmethod
|
||||
async def handle_new(cls, instance: "PostInteraction"):
|
||||
def handle_new(cls, instance: "PostInteraction"):
|
||||
"""
|
||||
Creates all needed fan-out objects for a new PostInteraction.
|
||||
"""
|
||||
interaction = await instance.afetch_full()
|
||||
# Boost: send a copy to all people who follow this user (limiting
|
||||
# to just local follows if it's a remote boost)
|
||||
# Pin: send Add activity to all people who follow this user
|
||||
if (
|
||||
interaction.type == interaction.Types.boost
|
||||
or interaction.type == interaction.Types.pin
|
||||
):
|
||||
for target in await interaction.aget_targets():
|
||||
await FanOut.objects.acreate(
|
||||
if instance.type == instance.Types.boost or instance.type == instance.Types.pin:
|
||||
for target in instance.get_targets():
|
||||
FanOut.objects.create(
|
||||
type=FanOut.Types.interaction,
|
||||
identity=target,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
# Like: send a copy to the original post author only,
|
||||
# if the liker is local or they are
|
||||
elif interaction.type == interaction.Types.like:
|
||||
if interaction.identity.local or interaction.post.local:
|
||||
await FanOut.objects.acreate(
|
||||
elif instance.type == instance.Types.like:
|
||||
if instance.identity.local or instance.post.local:
|
||||
FanOut.objects.create(
|
||||
type=FanOut.Types.interaction,
|
||||
identity_id=interaction.post.author_id,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
identity_id=instance.post.author_id,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
# Vote: send a copy of the vote to the original
|
||||
# post author only if it's a local interaction
|
||||
# to a non local post
|
||||
elif interaction.type == interaction.Types.vote:
|
||||
if interaction.identity.local and not interaction.post.local:
|
||||
await FanOut.objects.acreate(
|
||||
elif instance.type == instance.Types.vote:
|
||||
if instance.identity.local and not instance.post.local:
|
||||
FanOut.objects.create(
|
||||
type=FanOut.Types.interaction,
|
||||
identity_id=interaction.post.author_id,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
identity_id=instance.post.author_id,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
else:
|
||||
raise ValueError("Cannot fan out unknown type")
|
||||
# And one for themselves if they're local and it's a boost
|
||||
if (
|
||||
interaction.type == PostInteraction.Types.boost
|
||||
and interaction.identity.local
|
||||
):
|
||||
await FanOut.objects.acreate(
|
||||
identity_id=interaction.identity_id,
|
||||
if instance.type == PostInteraction.Types.boost and instance.identity.local:
|
||||
FanOut.objects.create(
|
||||
identity_id=instance.identity_id,
|
||||
type=FanOut.Types.interaction,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
return cls.fanned_out
|
||||
|
||||
@classmethod
|
||||
async def handle_undone(cls, instance: "PostInteraction"):
|
||||
def handle_undone(cls, instance: "PostInteraction"):
|
||||
"""
|
||||
Creates all needed fan-out objects to undo a PostInteraction.
|
||||
"""
|
||||
interaction = await instance.afetch_full()
|
||||
# Undo Boost: send a copy to all people who follow this user
|
||||
# Undo Pin: send a Remove activity to all people who follow this user
|
||||
if (
|
||||
interaction.type == interaction.Types.boost
|
||||
or interaction.type == interaction.Types.pin
|
||||
):
|
||||
async for follow in interaction.identity.inbound_follows.select_related(
|
||||
if instance.type == instance.Types.boost or instance.type == instance.Types.pin:
|
||||
for follow in instance.identity.inbound_follows.select_related(
|
||||
"source", "target"
|
||||
):
|
||||
if follow.source.local or follow.target.local:
|
||||
await FanOut.objects.acreate(
|
||||
FanOut.objects.create(
|
||||
type=FanOut.Types.undo_interaction,
|
||||
identity_id=follow.source_id,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
# Undo Like: send a copy to the original post author only
|
||||
elif interaction.type == interaction.Types.like:
|
||||
await FanOut.objects.acreate(
|
||||
elif instance.type == instance.Types.like:
|
||||
FanOut.objects.create(
|
||||
type=FanOut.Types.undo_interaction,
|
||||
identity_id=interaction.post.author_id,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
identity_id=instance.post.author_id,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
else:
|
||||
raise ValueError("Cannot fan out unknown type")
|
||||
# And one for themselves if they're local and it's a boost
|
||||
if (
|
||||
interaction.type == PostInteraction.Types.boost
|
||||
and interaction.identity.local
|
||||
):
|
||||
await FanOut.objects.acreate(
|
||||
identity_id=interaction.identity_id,
|
||||
if instance.type == PostInteraction.Types.boost and instance.identity.local:
|
||||
FanOut.objects.create(
|
||||
identity_id=instance.identity_id,
|
||||
type=FanOut.Types.undo_interaction,
|
||||
subject_post=interaction.post,
|
||||
subject_post_interaction=interaction,
|
||||
subject_post=instance.post,
|
||||
subject_post_interaction=instance,
|
||||
)
|
||||
return cls.undone_fanned_out
|
||||
|
||||
|
@ -212,17 +198,7 @@ class PostInteraction(StatorModel):
|
|||
[e.subject_post for e in events if e.subject_post], identity
|
||||
)
|
||||
|
||||
### Async helpers ###
|
||||
|
||||
async def afetch_full(self):
|
||||
"""
|
||||
Returns a version of the object with all relations pre-loaded
|
||||
"""
|
||||
return await PostInteraction.objects.select_related(
|
||||
"identity", "post", "post__author"
|
||||
).aget(pk=self.pk)
|
||||
|
||||
async def aget_targets(self) -> Iterable[Identity]:
|
||||
def get_targets(self) -> Iterable[Identity]:
|
||||
"""
|
||||
Returns an iterable with Identities of followers that have unique
|
||||
shared_inbox among each other to be used as target.
|
||||
|
@ -237,13 +213,15 @@ class PostInteraction(StatorModel):
|
|||
# Include all followers that are following the boosts
|
||||
if self.type == self.Types.boost:
|
||||
query = query.filter(boosts=True)
|
||||
async for follow in query.select_related("source"):
|
||||
for follow in query.select_related("source"):
|
||||
targets.add(follow.source)
|
||||
|
||||
# Fetch the full blocks and remove them as targets
|
||||
async for block in self.identity.outbound_blocks.active().filter(
|
||||
mute=False
|
||||
).select_related("target"):
|
||||
for block in (
|
||||
self.identity.outbound_blocks.active()
|
||||
.filter(mute=False)
|
||||
.select_related("target")
|
||||
):
|
||||
try:
|
||||
targets.remove(block.target)
|
||||
except KeyError:
|
||||
|
|
|
@ -16,7 +16,6 @@ class PushSubscriptionSchema(BaseModel):
|
|||
keys: Keys
|
||||
alerts: dict[str, bool]
|
||||
policy: str
|
||||
server_key: str
|
||||
|
||||
|
||||
class Token(models.Model):
|
||||
|
|
|
@ -498,7 +498,7 @@ class PushSubscription(Schema):
|
|||
value = token.push_subscription
|
||||
if value:
|
||||
value["id"] = "1"
|
||||
value["server_key"] = settings.VAPID_PUBLIC_KEY
|
||||
value["server_key"] = settings.SETUP.VAPID_PUBLIC_KEY
|
||||
del value["keys"]
|
||||
return value
|
||||
else:
|
||||
|
|
|
@ -2,7 +2,6 @@ from functools import partial
|
|||
from typing import ClassVar
|
||||
|
||||
import pydantic
|
||||
from asgiref.sync import sync_to_async
|
||||
from django.core.files import File
|
||||
from django.db import models
|
||||
from django.utils.functional import lazy
|
||||
|
@ -97,16 +96,6 @@ class Config(models.Model):
|
|||
{"identity__isnull": True, "user__isnull": True, "domain__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def aload_system(cls):
|
||||
"""
|
||||
Async loads the system config options object
|
||||
"""
|
||||
return await sync_to_async(cls.load_values)(
|
||||
cls.SystemOptions,
|
||||
{"identity__isnull": True, "user__isnull": True, "domain__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def load_user(cls, user):
|
||||
"""
|
||||
|
@ -117,16 +106,6 @@ class Config(models.Model):
|
|||
{"identity__isnull": True, "user": user, "domain__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def aload_user(cls, user):
|
||||
"""
|
||||
Async loads the user config options object
|
||||
"""
|
||||
return await sync_to_async(cls.load_values)(
|
||||
cls.UserOptions,
|
||||
{"identity__isnull": True, "user": user, "domain__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def load_identity(cls, identity):
|
||||
"""
|
||||
|
@ -137,16 +116,6 @@ class Config(models.Model):
|
|||
{"identity": identity, "user__isnull": True, "domain__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def aload_identity(cls, identity):
|
||||
"""
|
||||
Async loads an identity config options object
|
||||
"""
|
||||
return await sync_to_async(cls.load_values)(
|
||||
cls.IdentityOptions,
|
||||
{"identity": identity, "user__isnull": True, "domain__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def load_domain(cls, domain):
|
||||
"""
|
||||
|
@ -157,16 +126,6 @@ class Config(models.Model):
|
|||
{"domain": domain, "user__isnull": True, "identity__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def aload_domain(cls, domain):
|
||||
"""
|
||||
Async loads an domain config options object
|
||||
"""
|
||||
return await sync_to_async(cls.load_values)(
|
||||
cls.DomainOptions,
|
||||
{"domain": domain, "user__isnull": True, "identity__isnull": True},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def set_value(cls, key, value, options_class, filters):
|
||||
config_field = options_class.__fields__[key]
|
||||
|
|
|
@ -16,7 +16,7 @@ class Command(BaseCommand):
|
|||
"--concurrency",
|
||||
"-c",
|
||||
type=int,
|
||||
default=30,
|
||||
default=15,
|
||||
help="How many tasks to run at once",
|
||||
)
|
||||
parser.add_argument(
|
||||
|
|
|
@ -12,7 +12,7 @@ class RequestRunner(View):
|
|||
For when you're on something serverless.
|
||||
"""
|
||||
|
||||
async def get(self, request):
|
||||
def get(self, request):
|
||||
# Check the token, if supplied
|
||||
if not settings.STATOR_TOKEN:
|
||||
return HttpResponseForbidden("No token set")
|
||||
|
@ -20,5 +20,5 @@ class RequestRunner(View):
|
|||
return HttpResponseForbidden("Invalid token")
|
||||
# Run on all models
|
||||
runner = StatorRunner(StatorModel.subclasses, run_for=2)
|
||||
handled = await runner.run()
|
||||
handled = runner.run()
|
||||
return HttpResponse(f"Handled {handled}")
|
||||
|
|
|
@ -58,7 +58,7 @@ class BlockStates(StateGraph):
|
|||
return cls.sent
|
||||
|
||||
@classmethod
|
||||
async def handle_awaiting_expiry(cls, instance: "Block"):
|
||||
def handle_awaiting_expiry(cls, instance: "Block"):
|
||||
"""
|
||||
Checks to see if there is an expiry we should undo
|
||||
"""
|
||||
|
|
|
@ -60,7 +60,7 @@ class FollowStates(StateGraph):
|
|||
return cls.local_requested
|
||||
|
||||
@classmethod
|
||||
async def handle_local_requested(cls, instance: "Follow"):
|
||||
def handle_local_requested(cls, instance: "Follow"):
|
||||
# TODO: Resend follow requests occasionally
|
||||
pass
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ class IdentityStates(StateGraph):
|
|||
return cls.updated
|
||||
|
||||
@classmethod
|
||||
async def handle_updated(cls, instance: "Identity"):
|
||||
def handle_updated(cls, instance: "Identity"):
|
||||
if instance.state_age > Config.system.identity_max_age:
|
||||
return cls.outdated
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import random
|
||||
import string
|
||||
|
||||
from asgiref.sync import sync_to_async
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
from django.db import models
|
||||
|
@ -18,18 +17,17 @@ class PasswordResetStates(StateGraph):
|
|||
new.transitions_to(sent)
|
||||
|
||||
@classmethod
|
||||
async def handle_new(cls, instance: "PasswordReset"):
|
||||
def handle_new(cls, instance: "PasswordReset"):
|
||||
"""
|
||||
Sends the password reset email.
|
||||
"""
|
||||
reset = await instance.afetch_full()
|
||||
if reset.new_account:
|
||||
await sync_to_async(send_mail)(
|
||||
if instance.new_account:
|
||||
send_mail(
|
||||
subject=f"{Config.system.site_name}: Confirm new account",
|
||||
message=render_to_string(
|
||||
"emails/account_new.txt",
|
||||
{
|
||||
"reset": reset,
|
||||
"reset": instance,
|
||||
"config": Config.system,
|
||||
"settings": settings,
|
||||
},
|
||||
|
@ -37,21 +35,21 @@ class PasswordResetStates(StateGraph):
|
|||
html_message=render_to_string(
|
||||
"emails/account_new.html",
|
||||
{
|
||||
"reset": reset,
|
||||
"reset": instance,
|
||||
"config": Config.system,
|
||||
"settings": settings,
|
||||
},
|
||||
),
|
||||
from_email=settings.SERVER_EMAIL,
|
||||
recipient_list=[reset.user.email],
|
||||
recipient_list=[instance.user.email],
|
||||
)
|
||||
else:
|
||||
await sync_to_async(send_mail)(
|
||||
send_mail(
|
||||
subject=f"{Config.system.site_name}: Reset password",
|
||||
message=render_to_string(
|
||||
"emails/password_reset.txt",
|
||||
{
|
||||
"reset": reset,
|
||||
"reset": instance,
|
||||
"config": Config.system,
|
||||
"settings": settings,
|
||||
},
|
||||
|
@ -59,13 +57,13 @@ class PasswordResetStates(StateGraph):
|
|||
html_message=render_to_string(
|
||||
"emails/password_reset.html",
|
||||
{
|
||||
"reset": reset,
|
||||
"reset": instance,
|
||||
"config": Config.system,
|
||||
"settings": settings,
|
||||
},
|
||||
),
|
||||
from_email=settings.SERVER_EMAIL,
|
||||
recipient_list=[reset.user.email],
|
||||
recipient_list=[instance.user.email],
|
||||
)
|
||||
return cls.sent
|
||||
|
||||
|
@ -96,13 +94,3 @@ class PasswordReset(StatorModel):
|
|||
token="".join(random.choice(string.ascii_lowercase) for i in range(42)),
|
||||
new_account=not user.password,
|
||||
)
|
||||
|
||||
### Async helpers ###
|
||||
|
||||
async def afetch_full(self):
|
||||
"""
|
||||
Returns a version of the object with all relations pre-loaded
|
||||
"""
|
||||
return await PasswordReset.objects.select_related(
|
||||
"user",
|
||||
).aget(pk=self.pk)
|
||||
|
|
Loading…
Reference in New Issue