+++
+++

# Activity

an Activity is just an object that has an `actor`. it represents an action that was performed.

{{<toc>}}

## activities in activitypub

activities are meant to be POSTed to the outbox in C2S (by the Client), then if the Server is also a Federated Server, they get delivered to recipients' inboxes via POST to inbox (by the Federated Server)

for C2S: if it has `actor` then do not wrap it in a Create when it gets POSTed to outbox. otherwise, per [[AP § 6.2.1 "Object creation without a Create Activity"](https://www.w3.org/TR/activitypub/#object-without-create)]:
- make a new `Create` to wrap the object in `object`
- copy over `to`/`cc`/`bto`/`bcc`/`audience` from the object to the activity.
- [not explicitly stated:] set `actor` on the activity equal to the current authorized user, then copy that over to `object.attributedTo`
- generate an `id` for both the `Create` and the `object`, unless it is transient [[how do we determine this? perhaps a client explicitly specifies `id=null`?]]
- return the `id` of the activity via the `Location` header

for S2S: check `to`/`cc`/`bto`/`bcc`/`audience` on the activity. dereference any collections with a recursion limit (possibly n=1). add all discovered inboxes to a list. remove `bto`/`bcc`. POST to the list of discovered inboxes.

some activity types have side-effects defined in the activitypub spec, sections 6 (c2S) and 7 (s2s)

### (any Activity)

if it has `actor` then do not wrap it in a Create when it gets POSTed to outbox

- C2S: MUST assign `id` to the activity, ignoring anything that might be set by the Client, unless it is transient [[how to determine this?]]
- C2S: add it to the current actor's outbox [[if not transient?]]
- C2S: Return HTTP `201 Created`, `Location: <id>`
- S2S: warning, if it's an extension activity type then its side effects may not be understood. there may be fallback strategies to display `name`/`summary`/`content`

### Create

### Update

### Delete

### Add

### Remove

### Follow

### Like

### Block (C2S only)

### Announce (S2S only)

### Accept (S2S only)

### Reject (S2S only)

### Undo

## activities in the fediverse

in practice and in actuality, the "fediverse" largely does not conform to any of the 3 activitypub profiles. because c2s is not used, there are basically no Clients or Servers. and even on the s2s side, the side effects described by activitypub are not applied in any meaningful way. the *real* side effects vary per project. it can be argued that the fediverse is actually not built on activitypub, but rather, it is built on activitystreams 2.0 + linked data notifications. (it is a little-known fact that the `inbox` property in activitypub is actually `ldp:inbox` as defined by the linked data platform.)

### mastodon

supported activity types <https://github.com/mastodon/mastodon/tree/main/app/lib/activitypub/activity>

- Accept (accept a follow request)
- Add (adds hashtag or status to featured collection)
- Announce (reblog a status)
- Block (block an account)
- Create (create a message or status)
- Delete (delete account or status)
- Flag (report accounts and/or statuses)
- Follow (request to follow a local account)
- Like (favourite a status)
- Move (migrate an account's followers)
- Reject (reject follow request or remove follower)
- Remove (removes hashtag or status from featured collection)
- Undo (undoes some activities if possible)
- Update (update account info or edit a status)

#### extended logic

- **Accept**
	- **Accept Follow** -- authorize a follow request
		- (when relay is findable by `object` as follow_activity_id)
		- (when `object` is uri of existing follow request)
		- (when `object` is embedded Follow)
			- **Accept Follow `<Account>`**
- **Add**
	- (must have `target`)
	- (`target` must be a `toot:featured` collection)
	- (`object` must be inlined?)
	- **Add Hashtag to `target<featured>`** -- feature a hashtag
		- (takes `object.name` and removes prefix `#`)
		- (creates FeaturedTag entity for the `actor`'s account)
	- **Add `object<Status>` to `target<featured>`** -- pin a status
		- (`object` must be transformable to status)
		- (status must be authored by `actor`)
		- (status must not already be pinned)
- **Announce**
	- (must be related to local activity)
		- (i.e. `actor<Account>` followed by local accounts)
		- (or requested through relay)
		- (or `object` refers to a status whose account is local)
	- (`object` resolves to a status)
	- **Announce `object<Status>`** -- creates a reblog of a status
		- (stop if:)
			- (no status)
			- (status not boostable)
			- (requested through relay)
		- (find existing reblog or create)
- **Block**
	- (`object` resolves to an account)
		- (the resolved account exists and is local)
	- **Block `object<Account>`** -- block an account
		- (unfollow the `object<Account>`)
		- (force `object<Account>` to unfollow you)
		- (reject any follow requests from `object<Account>`)
		- (create a block asynchronously)
- **Create**
	- (dereference the `object`)
	- **Create EncryptedMessage** -- creates an encrypted message
		- (tries to find a device id)
		- (extracts `messageType`, `cipherText`, `digest`, `messageFranking`)
	- **Create `object<Status>`** -- creates a status
		- (rejected if)
			- (unsupported object type)
				- (`object` is a string)
				- (not in supported types)
					- Note
					- Question
				- (not in converted types)
					- Image
					- Audio
					- Video
					- Article
					- Page
					- Event
			- (or invalid origin)
			- (or tombstone exists for `object` uri)
			- (or not related to local activity)
- **Delete**
	- (if `actor` matches `object`)
		- **Delete `object<Account>`** -- delete your own account
	- **Delete `object<Status>`** -- delete a status
		- (create tombstone unless origin is invalid)
		- (forward deletion if forwardable)
		- (remove status from database and timelines)
- **Flag**
	- (`object` array is resolved as accounts and statuses)
		- (then filtered for local)
	- **Flag `object<Account,Status>`** -- report an account and/or statuses
		- (foreach account get reported statuses)
		- (create a report against the account w/ optional status ids and content)
- **Follow**
	- (`object` must be a local account that exists)
	- **Follow `object<Account>`** -- request to follow a local account
		- (create or update follow request)
		- (auto-reject if:)
			- (`object<Account>` is blocking `actor<Account>`)
			- (`object<Account>` is domain-blocking `actor`'s domain)
			- (`object<Account>` has moved/redirected)
			- (`object<Account>` is the instance actor)
		- (send an Accept Follow if a follow already exists)
		- (otherwise create a follow request)
			- (if you are silenced or they are locked, send frq notification)
			- (otherwise send Accept Follow and follow notification)
- **Like**
	- (resolve status from `object`)
	- **Like `object<Status>`** -- favourite a status
		- (stop if:)
			- (no status resolved)
			- (status is not from a local account)
			- (delete arrived first)
			- (you already favourited this status)
		- (create a favourite by `actor<Account>` for `object<Status>`)
- **Move**
	- (`actor` must match `object` and resolve to account)
	- (resolve `target` as account)
	- **Move `object<Account>` to `target<Account>`** -- migrate your followers
		- (stop if:)
			- (no `target<Account>`)
			- (`target<Account>` is suspended)
			- (`target.alsoKnownAs` doesn't include `object`)
		- (set a redirect)
		- (async move followers from `object<Account>` to `target<Account>`)
- **Reject**
	- **Reject Follow** -- reject a follow request or remove follower
		- (when relay is findable by `object` as follow_activity_id)
		- (when `object` is uri of existing follow request)
		- (when `object` is uri of existing follow)
			- (call UnfollowService for `actor<Account>`)
		- (when `object` is embedded Follow)
			- **Reject Follow `Follow.object<Account>`**
- **Remove**
	- (must have `target`)
	- (`target` must be a `toot:featured` collection)
	- (`object` must be inlined?)
	- **Remove Hashtag from `target<featured>`** -- unfeature a hashtag
		- (takes `object.name` and removes prefix `#`)
		- (deletes FeaturedTag entity for the `actor`'s account)
	- **Remove `object<Status>` from `target<featured>`** -- unpin a status
		- (`object` must be transformable to status)
		- (status must be authored by `actor`)
		- (destroy pin if existing pin found)
- **Undo**
	- (`object` should be inlined or else it may not be handled)
	- **Undo Announce** -- unreblog a status
		- (stop if no `Announce.id`)
		- (resolve `Announce.id` as status reblog)
		- (call RemoveStatusService on status)
	- **Undo Accept** -- unfollow an account [yes this is the assumption]
		- (find follow by `object.object.id` and revoke it)
	- **Undo Follow**
		- (resolve `object.object` as account)
			- (stop if not exists or not local)
		- **Undo Follow `<Account>`** -- unfollow an account
			- (`Undo.actor` unfollows `Follow.object<Account>` if following)
	- **Undo Like**
		- (resolve `object.object` as status)
		- (stop if no status or if status is not local)
		- **Undo Like `<Status>`** -- unfavourite a status
			- (if `actor` has favourited the status:)
				- (find a favourite on that status by that account)
				- (destroy it)
	- **Undo Block**
		- (resolve `object.object` as account)
		- (stop if not exists or not local)
		- **Undo Block `<Account>`** --unblock an account
			- (call UnblockService if `actor` is blocking `Block.object<Account>`)
	- **Undo `object<IRI>`**
		- (try_undo_announce)
			- (find reblogged status by `object` uri and `actor`)
			- (if found, remove reblog and stop, else continue)
		- (try_undo_accept)
			- (do nothing, continue) [because Accept uri is not stored]
		- (try_undo_follow)
			- (find `actor<Account>` follow request/relation by `object` uri)
			- (if found, destroy it and stop, else continue)
		- (try_undo_like)
			- (do nothing, continue) ["too costly", no index by Like uri]
		- (try_undo_block)
			- (find `actor<Account>` block by `object` uri)
			- (if found, call UnblockService and stop, else continue)
- **Update**
	- (dereference `object`)
	- (if `object.type` in `Application Group Organization Person Service`)
		- **Update `object<Account>`** -- update an account's info
			- (stop if `actor.id` does not match `object.id`)
			- (call ProcessAccountService)
	- (else if `object.type` in `Note Question`)
		- **Update `object<Status>`** -- edit a status
			- (stop if invalid origin)
			- (resolve `object` as status)
			- (stop if no status)
			- (call ProcessStatusUpdateService)

### pixelfed

<https://github.com/pixelfed/pixelfed/blob/dev/app/Util/ActivityPub/Inbox.php>

(seems to require inlining in a lot of places? not 100% sure but that's what it looks like to me)

- Add
	- (must be inlined?)
	- Add Story (not final)
- Create
	- (requires `to` for some reason, so `cc` only will break)
	- Create Question
	- (a single `to` item will create a DM if no `cc`)
	- Create Note.inReplyTo
	- Create Note.attachment
- Follow
	- Follow `object<Profile>`
- Announce
	- Announce `object<Status>`
- Accept
	- Accept Follow (anything else will return immediately)
- Delete
	- Delete `object<Profile>` (if `object` == `actor` and is valid string uri)
	- Delete [Person, Tombstone, Story] (???)
		- Delete Person
		- Delete Tombstone (???)
		- Delete Story (not final)
- Like
	- Like `object<Status>`
- Reject
	- (does nothing)
- Undo
	- (must be inlined)
	- Undo Accept
		- (does nothing)
	- Undo Announce
	- Undo Block
		- (does nothing)
	- Undo Follow
	- Undo Like
- View
	- View Story (not final)
		- (also seems to get story id by whatever is after the last slash?)
- Story:Reaction (not final; undocumented extension)
	- (`id` and `actor` must be valid urls)
	- (`inReplyTo` and `to` must be local)
	- (`object` must not resolve to Status)
	- (seems to get story id by whatever is after the last slash?)
- Story:Reply (not final; undocumented extension)
	- (`id` and `actor` must be valid urls)
	- (`inReplyTo` and `to` must be local)
	- (`object` must not resolve to Status)
	- (seems to get story id by whatever is after the last slash?)
- Update (commented out)

### misskey

<https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/core/activitypub/type.ts>

- Create
- Delete
- Update
- Read
- Undo
- Follow
- Accept
- Reject
- Add
- Remove
- Like | EmojiReaction | EmojiReact
- Announce
- Block
- Flag

<https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/core/activitypub/ApInboxService.ts>

### pleroma

ObjectValidator <https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/web/activity_pub/object_validator.ex>

validate()

- Block
- Undo
- Delete
- Create ChatMessage
- Create [Question Answer Audio Video Event Article Note Page]
- [Event Question Audio Video Article Note Page]
	- Event
	- Question
	- Audio
	- Video
	- Article
	- Note
	- Page
- Update [Question Answer Audio Video Event Article Note Page]
- [Accept Reject Follow Update Like EmojiReact Announce]
	- Accept
	- Reject
	- Follow
	- Update
	- Like
	- EmojiReact
	- Announce
	- ChatMessage
	- Answer
- [Add Remove]

SideEffects <https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/web/activity_pub/side_effects.ex>

handle()

- Accept
	- Accept Follow
- Reject
	- Reject Follow
- Follow
- Block
- Update
	- Update `object<User>`
	- Update `object<Object>`
- Like
- Create
	- Create ChatMessage
	- Create Question
	- Create Answer
	- Create [Audio Video Event Article Note Page]
- Announce
- Undo
	- Undo Like
	- Undo EmojiReact
	- Undo Announce
	- Undo Block
- EmojiReact
- Delete
- Add
- Remove

Transmogrifier <https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/web/activity_pub/transmogrifier.ex>

handle_incoming()

- Flag
- Listen Audio
- Like._misskey_reaction
- Create [Question Answer ChatMessage Audio Video Event Article Note Page]
- [Like EmojiReact Announce Add Remove]
	- (fetch `actor` and `object`)
- [Update Block Follow Accept Reject]
	- (fetch `actor`)
- Delete
	- (check if Create exists)
- Undo Follow
- Undo
	- (get `object` by `id` and expand it)
- Move

prepare_outgoing()

- [Create Listen]
- Update `object<updatable>`
	- [Note Question Audio Video Event Article Page]
- Announce
- Accept -> Accept Follow
- Reject -> Reject Follow
- Answer -> Note