summaryrefslogtreecommitdiffstats
path: root/activities
diff options
context:
space:
mode:
authorAndrew Godwin2022-11-12 21:14:21 -0700
committerAndrew Godwin2022-11-12 21:14:21 -0700
commit878f56b411279cd9865a7ec05f1d14c9f70f6187 (patch)
tree93f3c65e109a014041e4380a854bdf8b4dd7fe6d /activities
parentdd4328ae523bb375dd871e85d1bacd9311e87a89 (diff)
downloadtakahe-878f56b411279cd9865a7ec05f1d14c9f70f6187.tar.gz
takahe-878f56b411279cd9865a7ec05f1d14c9f70f6187.tar.bz2
takahe-878f56b411279cd9865a7ec05f1d14c9f70f6187.zip
Post URIs and host-meta
Diffstat (limited to 'activities')
-rw-r--r--activities/migrations/0003_alter_post_object_uri.py18
-rw-r--r--activities/models/fan_out.py2
-rw-r--r--activities/models/post.py54
3 files changed, 52 insertions, 22 deletions
diff --git a/activities/migrations/0003_alter_post_object_uri.py b/activities/migrations/0003_alter_post_object_uri.py
new file mode 100644
index 0000000..4f98bc9
--- /dev/null
+++ b/activities/migrations/0003_alter_post_object_uri.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.3 on 2022-11-13 03:09
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("activities", "0002_fan_out"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="post",
+ name="object_uri",
+ field=models.CharField(blank=True, max_length=500, null=True, unique=True),
+ ),
+ ]
diff --git a/activities/models/fan_out.py b/activities/models/fan_out.py
index 96e8df7..958fbe2 100644
--- a/activities/models/fan_out.py
+++ b/activities/models/fan_out.py
@@ -32,7 +32,7 @@ class FanOutStates(StateGraph):
await HttpSignature.signed_request(
uri=fan_out.identity.inbox_uri,
body=canonicalise(post.to_create_ap()),
- private_key=post.author.public_key,
+ private_key=post.author.private_key,
key_id=post.author.public_key_id,
)
return cls.sent
diff --git a/activities/models/post.py b/activities/models/post.py
index 4c40033..ec5e629 100644
--- a/activities/models/post.py
+++ b/activities/models/post.py
@@ -7,7 +7,7 @@ from django.utils import timezone
from activities.models.fan_out import FanOut
from activities.models.timeline_event import TimelineEvent
from core.html import sanitize_post
-from core.ld import format_date
+from core.ld import format_ld_date, parse_ld_date
from stator.models import State, StateField, StateGraph, StatorModel
from users.models.follow import Follow
from users.models.identity import Identity
@@ -53,7 +53,7 @@ class Post(StatorModel):
local = models.BooleanField()
# The canonical object ID
- object_uri = models.CharField(max_length=500, blank=True, null=True)
+ object_uri = models.CharField(max_length=500, blank=True, null=True, unique=True)
# Who should be able to see this Post
visibility = models.IntegerField(
@@ -145,18 +145,22 @@ class Post(StatorModel):
"""
# Send a copy to all people who follow this user
post = await self.afetch_full()
- async for follow in post.author.inbound_follows.all():
+ async for follow in post.author.inbound_follows.select_related(
+ "source", "target"
+ ):
+ if follow.source.local or follow.target.local:
+ await FanOut.objects.acreate(
+ identity_id=follow.source_id,
+ type=FanOut.Types.post,
+ subject_post=post,
+ )
+ # And one for themselves if they're local
+ if post.author.local:
await FanOut.objects.acreate(
- identity_id=follow.source_id,
+ identity_id=post.author_id,
type=FanOut.Types.post,
subject_post=post,
)
- # And one for themselves
- await FanOut.objects.acreate(
- identity_id=post.author_id,
- type=FanOut.Types.post,
- subject_post=post,
- )
def to_ap(self) -> Dict:
"""
@@ -165,7 +169,7 @@ class Post(StatorModel):
value = {
"type": "Note",
"id": self.object_uri,
- "published": format_date(self.created),
+ "published": format_ld_date(self.created),
"attributedTo": self.author.actor_uri,
"content": self.safe_content,
"to": "as:Public",
@@ -190,7 +194,7 @@ class Post(StatorModel):
### ActivityPub (inbound) ###
@classmethod
- def by_ap(cls, data, create=False) -> "Post":
+ def by_ap(cls, data, create=False, update=False) -> "Post":
"""
Retrieves a Post instance by its ActivityPub JSON object.
@@ -198,25 +202,33 @@ class Post(StatorModel):
Raises KeyError if it's not found and create is False.
"""
# Do we have one with the right ID?
+ created = False
try:
- return cls.objects.get(object_uri=data["id"])
+ post = cls.objects.get(object_uri=data["id"])
except cls.DoesNotExist:
if create:
# Resolve the author
author = Identity.by_actor_uri(data["attributedTo"], create=create)
- return cls.objects.create(
+ post = cls.objects.create(
+ object_uri=data["id"],
author=author,
content=sanitize_post(data["content"]),
- summary=data.get("summary", None),
- sensitive=data.get("as:sensitive", False),
- url=data.get("url", None),
local=False,
- # TODO: to
- # TODO: mentions
- # TODO: visibility
)
+ created = True
else:
raise KeyError(f"No post with ID {data['id']}", data)
+ if update or created:
+ post.content = sanitize_post(data["content"])
+ post.summary = data.get("summary", None)
+ post.sensitive = data.get("as:sensitive", False)
+ post.url = data.get("url", None)
+ post.authored = parse_ld_date(data.get("published", None))
+ # TODO: to
+ # TODO: mentions
+ # TODO: visibility
+ post.save()
+ return post
@classmethod
def handle_create_ap(cls, data):
@@ -227,7 +239,7 @@ class Post(StatorModel):
if data["actor"] != data["object"]["attributedTo"]:
raise ValueError("Create actor does not match its Post object", data)
# Create it
- post = cls.by_ap(data["object"], create=True)
+ post = cls.by_ap(data["object"], create=True, update=True)
# Make timeline events as appropriate
for follow in Follow.objects.filter(target=post.author, source__local=True):
TimelineEvent.add_post(follow.source, post)