Skip to content

Conversation

@aaronjae22
Copy link
Collaborator

Relationships Overview

Actor

The Actor is the core entity (user or agent) that interacts with the system. It:

  • Authors content, such as Notes.
  • Performs Activities (e.g., creating, liking, or following).
  • Owns a PortabilityOutbox that aggregates all portable activities.

Activity

The Activity is an action performed by an Actor. It:

  • References the Actor who performed the action.
  • May link to a Note as its target object (e.g., a Create activity for a Note).

Note

The Note represents textual content authored by an Actor. It:

  • Is attributed to an Actor (e.g., the author of the Note).
  • Can be the object of an Activity (e.g., a Create activity targets a Note).

PortabilityOutbox

The PortabilityOutbox serves as an aggregate of an Actor’s portable activities. It:

  • Belongs to an Actor.
  • Contains multiple Activities performed by the Actor.

Relationships in Detail

a. Actor → Activity

  • Type: One-to-Many (via ForeignKey)
  • Each Actor can perform multiple Activities.
    • Alice (Actor) performs:
      • A Create activity for a Note.
      • A Like activity for another user’s post.

actor = models.ForeignKey(Actor, on_delete=models.CASCADE, related_name="activities")

b. Actor → Note

  • Type: One-to-Many (via ForeignKey)
  • Each Note is authored by a single Actor.
  • An Actor can author multiple Notes.
    • Alice (Actor) writes:
      • “This is my first post!” (Note 1).
      • “Another update from Alice!” (Note 2).

attributed_to = models.ForeignKey(Actor, on_delete=models.CASCADE, related_name="notes")

c. Activity → Note

  • Type: One-to-One (via OneToOneField)
  • Some Activities, like Create, are directly tied to a single Note as their object.
    • A Create activity references:
      • “This is my first post!” (Note 1).
    • Other activities, like Like or Follow, may not reference a Note.
note = models.OneToOneField(
    "Note",
    on_delete=models.CASCADE,
    null=True,
    blank=True,
    related_name="activity"
)

d. Actor → PortabilityOutbox

  • Type: One-to-Many (via ForeignKey)
  • Each Actor owns a PortabilityOutbox that aggregates their Activities.
    • Alice (Actor) has an Outbox containing:
      • A Create activity for a Note.
      • A Like activity for Bob’s post.

actor = models.ForeignKey(Actor, on_delete=models.CASCADE, related_name="portability_outbox")

e. PortabilityOutbox → Activity

  • Type: Many-to-Many (via ManyToManyField)
  • The PortabilityOutbox collects multiple Activities performed by the Actor.
    • Alice’s Outbox contains:
      • A Create activity.
      • A Like activity.
    • This allows all activities to be exported in a LOLA-compliant format.

activities = models.ManyToManyField(Activity, related_name="outbox_collections")

Real-World Example

Use Case: Alice writes a post and likes Bob’s post.

  1. Actor Creation:
    • Alice (Actor) is created with a username.
  2. Note Creation:
    • Alice writes “Hello, world!” (Note).
  3. Activity Creation:
    • Alice performs a Create activity for the Note.
    • Alice performs a Like activity for Bob’s post.
  4. PortabilityOutbox Update:
    • Both activities (Create and Like) are added to Alice’s PortabilityOutbox.
# Step 1: Create Actor
user = User.objects.create(username="alice")
alice = Actor.objects.create(user=user, username="alice", full_name="Alice Example")

# Step 2: Create Note
note = Note.objects.create(
    linked_to=alice,
    content="Hello, world!",
    visibility="public"
)

# Step 3: Create Activities
create_activity = Activity.objects.create(
    actor=alice,
    type="Create",
    note=note,
    visibility="public"
)

like_activity = Activity.objects.create(
    actor=alice,
    type="Like",
    content="Liked Bob's post."
)

# Step 4: Add to PortabilityOutbox
outbox = PortabilityOutbox.objects.create(actor=alice)
outbox.activities.add(create_activity, like_activity)

# Print Outbox JSON-LD
print(outbox.get_json_ld())

JSON-LD Representation

Outbox JSON-LD

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "OrderedCollection",
  "id": "https://example.com/users/alice/outbox",
  "totalItems": 2,
  "items": [
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Create",
      "id": "https://example.com/activities/1",
      "actor": "https://example.com/users/alice",
      "published": "2024-11-08T12:00:00Z",
      "visibility": "public",
      "object": {
        "@context": "https://www.w3.org/ns/activitystreams",
        "type": "Note",
        "id": "https://example.com/notes/1",
        "attributedTo": "https://example.com/users/alice",
        "content": "Hello, world!",
        "published": "2024-11-08T12:00:00Z",
        "visibility": "public"
      }
    },
    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "type": "Like",
      "id": "https://example.com/activities/2",
      "actor": "https://example.com/users/alice",
      "published": "2024-11-08T12:01:00Z",
      "visibility": "public",
      "content": "Liked Bob's post."
    }
  ]
}

@aaronjae22 aaronjae22 requested a review from lisad December 3, 2024 16:34
@aaronjae22 aaronjae22 added the enhancement New feature or request label Dec 3, 2024
@aaronjae22
Copy link
Collaborator Author

aaronjae22 commented Dec 3, 2024

Closes #4
Closes #5

Copy link
Member

@lisad lisad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's lots to be done here but this is such an early project you should merge this and keep moving

@aaronjae22 aaronjae22 merged commit 9e44059 into main Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants