Skip to content

Commit

Permalink
Fixed jointakahe#616: Do followers-only properly
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewgodwin committed Jul 22, 2023
1 parent 1dd076f commit 759d5ac
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 8 deletions.
8 changes: 7 additions & 1 deletion activities/models/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ def to_ap(self) -> dict:
"""
Returns the AP JSON for this object
"""
self.author.ensure_uris()
value = {
"to": [],
"cc": [],
Expand Down Expand Up @@ -655,11 +656,14 @@ def to_ap(self) -> dict:
if self.edited:
value["updated"] = format_ld_date(self.edited)
# Targeting
# TODO: Add followers object
if self.visibility == self.Visibilities.public:
value["to"].append("as:Public")
elif self.visibility == self.Visibilities.unlisted:
value["cc"].append("as:Public")
elif (
self.visibility == self.Visibilities.followers and self.author.followers_uri
):
value["to"].append(self.author.followers_uri)
# Mentions
for mention in self.mentions.all():
value["tag"].append(mention.to_ap_tag())
Expand Down Expand Up @@ -922,6 +926,8 @@ def by_ap(cls, data, create=False, update=False, fetch_author=False) -> "Post":
post.visibility = Post.Visibilities.public
elif "public" in cc or "as:public" in cc:
post.visibility = Post.Visibilities.unlisted
elif post.author.followers_uri in to:
post.visibility = Post.Visibilities.followers
# Attachments
# These have no IDs, so we have to wipe them each time
post.attachments.all().delete()
Expand Down
9 changes: 7 additions & 2 deletions docs/releases/0.10.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
0.9
===
0.10
====

*Released: Not Yet Released*

Expand All @@ -15,6 +15,11 @@ This release's major changes:

* TBC

Minor changes also include:

* Followers-only mode now works correctly inbound and outbound (though outbound
may need the other server to refresh the profile first).

If you'd like to help with code, design, or other areas, see
:doc:`/contributing` to see how to get in touch.

Expand Down
42 changes: 42 additions & 0 deletions tests/activities/models/test_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,3 +499,45 @@ def test_post_hashtag_to_ap(identity: Identity, config_system):
]
assert "#world" in ap["object"]["content"]
assert 'rel="tag"' in ap["object"]["content"]


@pytest.mark.django_db
@pytest.mark.parametrize(
"visibility",
[
Post.Visibilities.public,
Post.Visibilities.unlisted,
Post.Visibilities.followers,
Post.Visibilities.mentioned,
],
)
def test_post_targets_to_ap(
identity: Identity, other_identity: Identity, visibility: Post.Visibilities
):
"""
Ensures that posts have the right targets in AP form.
"""

# Make a post
post = Post.objects.create(
content="<p>Hello @other</p>",
author=identity,
local=True,
visibility=visibility,
)
post.mentions.add(other_identity)

# Check its AP targets
ap_dict = post.to_ap()
if visibility == Post.Visibilities.public:
assert ap_dict["to"] == ["as:Public"]
assert ap_dict["cc"] == [other_identity.actor_uri]
elif visibility == Post.Visibilities.unlisted:
assert "to" not in ap_dict
assert ap_dict["cc"] == ["as:Public", other_identity.actor_uri]
elif visibility == Post.Visibilities.followers:
assert ap_dict["to"] == [identity.followers_uri]
assert ap_dict["cc"] == [other_identity.actor_uri]
elif visibility == Post.Visibilities.mentioned:
assert "to" not in ap_dict
assert ap_dict["cc"] == [other_identity.actor_uri]
26 changes: 21 additions & 5 deletions users/models/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,19 @@ def safe_metadata(self):
for data in self.metadata
]

def ensure_uris(self):
"""
Ensures that local identities have all the URIs populated on their fields
(this lets us add new ones easily)
"""
if self.local:
self.inbox_uri = self.actor_uri + "inbox/"
self.outbox_uri = self.actor_uri + "outbox/"
self.featured_collection_uri = self.actor_uri + "collections/featured/"
self.followers_uri = self.actor_uri + "followers/"
self.following_uri = self.actor_uri + "following/"
self.shared_inbox_uri = f"https://{self.domain.uri_domain}/inbox/"

### Alternate constructors/fetchers ###

@classmethod
Expand Down Expand Up @@ -482,12 +495,15 @@ def to_webfinger(self):
def to_ap(self):
from activities.models import Emoji

self.ensure_uris()
response = {
"id": self.actor_uri,
"type": self.actor_type.title(),
"inbox": self.actor_uri + "inbox/",
"outbox": self.actor_uri + "outbox/",
"featured": self.actor_uri + "collections/featured/",
"inbox": self.inbox_uri,
"outbox": self.outbox_uri,
"featured": self.featured_collection_uri,
"followers": self.followers_uri,
"following": self.following_uri,
"preferredUsername": self.username,
"publicKey": {
"id": self.public_key_id,
Expand All @@ -514,9 +530,9 @@ def to_ap(self):
"mediaType": media_type_from_filename(self.image.name),
"url": self.image.url,
}
if self.local:
if self.shared_inbox_uri:
response["endpoints"] = {
"sharedInbox": f"https://{self.domain.uri_domain}/inbox/",
"sharedInbox": self.shared_inbox_uri,
}
if self.metadata:
response["attachment"] = [
Expand Down

0 comments on commit 759d5ac

Please sign in to comment.