summaryrefslogtreecommitdiffstats
path: root/users
diff options
context:
space:
mode:
Diffstat (limited to 'users')
-rw-r--r--users/migrations/0005_follow_state_locked_until_follow_state_ready.py23
-rw-r--r--users/models/__init__.py4
-rw-r--r--users/models/domain.py2
-rw-r--r--users/models/follow.py14
-rw-r--r--users/models/identity.py16
-rw-r--r--users/shortcuts.py9
-rw-r--r--users/views/identity.py6
7 files changed, 53 insertions, 21 deletions
diff --git a/users/migrations/0005_follow_state_locked_until_follow_state_ready.py b/users/migrations/0005_follow_state_locked_until_follow_state_ready.py
new file mode 100644
index 0000000..3aba08e
--- /dev/null
+++ b/users/migrations/0005_follow_state_locked_until_follow_state_ready.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.1.3 on 2022-11-10 03:24
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("users", "0004_remove_follow_state_locked_and_more"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="follow",
+ name="state_locked_until",
+ field=models.DateTimeField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name="follow",
+ name="state_ready",
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/users/models/__init__.py b/users/models/__init__.py
index e1877bc..d46003f 100644
--- a/users/models/__init__.py
+++ b/users/models/__init__.py
@@ -1,6 +1,6 @@
from .block import Block # noqa
from .domain import Domain # noqa
-from .follow import Follow # noqa
-from .identity import Identity # noqa
+from .follow import Follow, FollowStates # noqa
+from .identity import Identity, IdentityStates # noqa
from .user import User # noqa
from .user_event import UserEvent # noqa
diff --git a/users/models/domain.py b/users/models/domain.py
index 8467ac3..4ac6ee9 100644
--- a/users/models/domain.py
+++ b/users/models/domain.py
@@ -55,7 +55,7 @@ class Domain(models.Model):
return cls.objects.create(domain=domain, local=False)
@classmethod
- def get_local_domain(cls, domain: str) -> Optional["Domain"]:
+ def get_domain(cls, domain: str) -> Optional["Domain"]:
try:
return cls.objects.get(
models.Q(domain=domain) | models.Q(service_domain=domain)
diff --git a/users/models/follow.py b/users/models/follow.py
index 04f90ee..3325a0b 100644
--- a/users/models/follow.py
+++ b/users/models/follow.py
@@ -6,13 +6,13 @@ from stator.models import State, StateField, StateGraph, StatorModel
class FollowStates(StateGraph):
- pending = State(try_interval=3600)
+ pending = State(try_interval=30)
requested = State()
accepted = State()
@pending.add_transition(requested)
- async def try_request(cls, instance):
- print("Would have tried to follow")
+ async def try_request(instance: "Follow"): # type:ignore
+ print("Would have tried to follow on", instance)
return False
requested.add_manual_transition(accepted)
@@ -73,11 +73,3 @@ class Follow(StatorModel):
follow.state = FollowStates.accepted
follow.save()
return follow
-
- def undo(self):
- """
- Undoes this follow
- """
- if not self.target.local:
- Task.submit("follow_undo", str(self.pk))
- self.delete()
diff --git a/users/models/identity.py b/users/models/identity.py
index 98262bc..5e2cd06 100644
--- a/users/models/identity.py
+++ b/users/models/identity.py
@@ -14,9 +14,21 @@ from django.utils import timezone
from OpenSSL import crypto
from core.ld import canonicalise
+from stator.models import State, StateField, StateGraph, StatorModel
from users.models.domain import Domain
+class IdentityStates(StateGraph):
+ outdated = State(try_interval=3600)
+ updated = State()
+
+ @outdated.add_transition(updated)
+ async def fetch_identity(identity: "Identity"): # type:ignore
+ if identity.local:
+ return True
+ return await identity.fetch_actor()
+
+
def upload_namer(prefix, instance, filename):
"""
Names uploaded images etc.
@@ -26,7 +38,7 @@ def upload_namer(prefix, instance, filename):
return f"{prefix}/{now.year}/{now.month}/{now.day}/{filename}"
-class Identity(models.Model):
+class Identity(StatorModel):
"""
Represents both local and remote Fediverse identities (actors)
"""
@@ -35,6 +47,8 @@ class Identity(models.Model):
# one around as well for making nice URLs etc.
actor_uri = models.CharField(max_length=500, unique=True)
+ state = StateField(IdentityStates)
+
local = models.BooleanField()
users = models.ManyToManyField("users.User", related_name="identities")
diff --git a/users/shortcuts.py b/users/shortcuts.py
index 65206a3..3e7618a 100644
--- a/users/shortcuts.py
+++ b/users/shortcuts.py
@@ -3,7 +3,7 @@ from django.http import Http404
from users.models import Domain, Identity
-def by_handle_or_404(request, handle, local=True, fetch=False):
+def by_handle_or_404(request, handle, local=True, fetch=False) -> Identity:
"""
Retrieves an Identity by its long or short handle.
Domain-sensitive, so it will understand short handles on alternate domains.
@@ -12,14 +12,17 @@ def by_handle_or_404(request, handle, local=True, fetch=False):
if "HTTP_HOST" not in request.META:
raise Http404("No hostname available")
username = handle
- domain_instance = Domain.get_local_domain(request.META["HTTP_HOST"])
+ domain_instance = Domain.get_domain(request.META["HTTP_HOST"])
if domain_instance is None:
raise Http404("No matching domains found")
domain = domain_instance.domain
else:
username, domain = handle.split("@", 1)
# Resolve the domain to the display domain
- domain = Domain.get_local_domain(request.META["HTTP_HOST"]).domain
+ domain_instance = Domain.get_domain(domain)
+ if domain_instance is None:
+ raise Http404("No matching domains found")
+ domain = domain_instance.domain
identity = Identity.by_username_and_domain(
username,
domain,
diff --git a/users/views/identity.py b/users/views/identity.py
index 41c7880..d02505f 100644
--- a/users/views/identity.py
+++ b/users/views/identity.py
@@ -17,7 +17,7 @@ from core.forms import FormHelper
from core.ld import canonicalise
from core.signatures import HttpSignature
from users.decorators import identity_required
-from users.models import Domain, Follow, Identity
+from users.models import Domain, Follow, Identity, IdentityStates
from users.shortcuts import by_handle_or_404
@@ -34,7 +34,7 @@ class ViewIdentity(TemplateView):
)
statuses = identity.statuses.all()[:100]
if identity.data_age > settings.IDENTITY_MAX_AGE:
- Task.submit("identity_fetch", identity.handle)
+ identity.transition_perform(IdentityStates.outdated)
return {
"identity": identity,
"statuses": statuses,
@@ -129,7 +129,7 @@ class CreateIdentity(FormView):
def form_valid(self, form):
username = form.cleaned_data["username"]
domain = form.cleaned_data["domain"]
- domain_instance = Domain.get_local_domain(domain)
+ domain_instance = Domain.get_domain(domain)
new_identity = Identity.objects.create(
actor_uri=f"https://{domain_instance.uri_domain}/@{username}@{domain}/actor/",
username=username,