Users need to review and revise the list of actors they have blocked. This FEP proposes a new collection property, the Blocked Collection, which contains the actors that a user has blocked.
doc: FEP-c648 Blocked Collection #111
evanp/fep:fep-c648 into main Signed-off-by: Evan Prodromou <evan@openearth.org>
The activitypub-express library (and projects based on it like Immers Space and Guppe groups) implement the blocked collection as well.
Since it wasn't a standard actor property already, it is currently nested under actor.streams. Agree with the proposal to promote it to an actor property, though.
Like in this proposal, we mimicked the followers/following collection by making this a collection of people (in our case, IRIs to actors). However, in retrospect, I think this was a mistake.
With the purpose of being able to manage your blocklist, just having an actor object is insufficient to construct a C2S activity the remove that person from the list. The Undo activity should be used to undo a past Block activity, but to construct an Undo you need a reference to that past Block activity rather than just its object. We ended up with a terrible server-side heuristic to allow sending Undo->Person and have it translate that into Undo->Block by looking up the block activity for that person.
Consider specifying the blocked collection as a collection of Block activities instead so that it would contain all the information necessary to manage that collection.
That sounds like a really good point! I'll change blocked from objects to activities. Thanks for the note!
Signed-off-by: Evan Prodromou <evan@openearth.org>
Thanks so much to @syndic-will for the note about activities versus actors. I've updated the proposal to list activities, and tried to give the reason why.
This actually raises a similar issue with liked in ActivityPub... there, the liked collection contains the objects, not the Like activities. So the parallel expectation would be to have blocked contain the blocked actors as well.
But it is also a valid and pressing use-case to have access to the original activity. I imagine that this would be accomplished by filtering/querying the outbox, if there were any support for filtering/querying...
With the purpose of being able to manage your blocklist, just having an actor object is insufficient to construct a C2S activity the remove that person from the list. The Undo activity should be used to undo a past Block activity, but to construct an Undo you need a reference to that past Block activity rather than just its object. We ended up with a terrible server-side heuristic to allow sending Undo->Person and have it translate that into Undo->Block by looking up the block activity for that person.
Another option might be to send an Undo Block where the Block is inlined or embedded, without an id. Like so:
{
"actor": <you>,
"type": "Undo",
"object": {
"actor": <you>,
"type": "Block",
"object": <some-actor>
}
}
This actually raises a similar issue with
likedin ActivityPub... there, thelikedcollection contains the objects, not the Like activities. So the parallel expectation would be to haveblockedcontain the blocked actors as well.
followers, following and liked all include objects.
likes and shares all include activities.
Should we change the name of blocked to be blocks or blocklist to make it clear that it includes activities?
I think from a Server's POV the main consideration is dropping interactions from blocked actors --> i.e. getting a list of all blocked actors
For a Client, the main consideration is being able to block and unblock easily, right?
So I guess a similar question is: how might you send an Undo Like with the <actor>.liked collection only containing the objects and not the activities? Pinging @syndic-will for their thoughts here... do you put a collection in <actor>.streams for Like activities as well? Do you handle <actor>.following and <actor>.followed the same with Follow and Accept Follow, so that you may later Undo or Reject them?
Personally, my mental model assumes that all activities end up in the <actor>.outbox due to C2S. But the <actor>.outbox returns different results based on who's asking. An unauthed request will not return Block activities, but an authed request by <actor> would return them. So I'd favor a blocked which contains the actors and not the activity, because that's what the server needs to work with. And an alternate mechanism to filter the outbox for certain activities.
I think from a Server's POV the main consideration is dropping interactions from blocked actors --> i.e. getting a list of all blocked actors
For a Client, the main consideration is being able to block and unblock easily, right?
So I guess a similar question is: how might you send an Undo Like with the
<actor>.likedcollection only containing the objects and not the activities? Pinging @syndic-will for their thoughts here... do you put a collection in<actor>.streamsfor Like activities as well? Do you handle<actor>.followingand<actor>.followedthe same with Follow and Accept Follow, so that you may later Undo or Reject them?
@trwnh The fact that many of the standard collections are specified to contain objects instead of their originating activities is what makes a C2S client so difficult to create. It's equally impossible to remove a follow or follower, unless you were to fetch the entire outbox history to track down that original activity, so we have terrible server-side heuristics for those as well.
Personally, my mental model assumes that all activities end up in the
<actor>.outboxdue to C2S. But the<actor>.outboxreturns different results based on who's asking. An unauthed request will not returnBlockactivities, but an authed request by<actor>would return them. So I'd favor ablockedwhich contains the actors and not the activity, because that's what the server needs to work with. And an alternate mechanism to filter the outbox for certain activities.
I think the blocked collection is pretty clearly defined as primarily serving the client (if a server needs its own blocklist it can retrieve those any way it wants with no standards needed), and any software that needs the object can simply extract it from activity.object. That's such a simple operation in comparison to the reverse which we all seem to recognize is very difficult - why make it difficult for the primary use case?
why make it difficult for the primary use case?
the use case i was thinking of was if actor in blocked a la if object in liked or if actor in followers or if actor in following as the existing/prevailing data model seems to be. having blocks be the "odd one out" makes it confusing. and i'm not sure it would have ever made sense to keep track of Accept Follow activities instead of directly keeping track of followers, for example.
basically, i see the problem you're having, and it is a valid problem, but it is part of an entire class of problems that should be solved with a common mechanism for filtering or querying the outbox for the activity you are looking for. or even filtering or querying any arbitrary collection. otherwise, you could very well imagine a follows collection, an accepts collection, a likes collection which conflicts with the already-existing likes collection, and so on. see FEP-5bf0 for an attempt at addressing this: https://socialhub.activitypub.rocks/t/fep-5bf0-collection-sorting-and-filtering/3095 -- the linked thread discusses query languages like SQL or SPARQL, and the current state of the proposal uses SHACL which i am not familiar with, but the general idea of having querying support makes sense. i could see it being one of the endpoints for the server, perhaps? but that's a different topic...
@trwnh it sounds like you think that this would be the server's internal representation of the blocklist. It's not! It's just the way an API client can retrieve this information.
The server would typically have a representation like an indexed relational database table to quickly look up the block relationship.
We're defining the on-the-wire API, not the internal representation. The main use cases for client apps are 1) view the blocked actors and 2) undo a block. I think we cover that pretty well with this collection.
I'd also say that as a principle developer experience should outweigh conceptual coherence. Parallelism would suggest that blocked would have the same kind of things as followers and following, but in this case we're hearing from at least one dev who found the lack of Activity info hampering.
Another note: I think we could do a separate FEP for ID-less undo. I really like @trwnh 's proposal to Undo a Block without an id but with the right object. We could do that for Undo on Follow, Like, Announce, etc. It's a pretty useful pattern!
Another note: I think we could do a separate FEP for ID-less undo. I really like @trwnh 's proposal to
UndoaBlockwithout anidbut with the rightobject. We could do that forUndoonFollow,Like,Announce, etc. It's a pretty useful pattern!
This does sound pretty awesome, and would solve most of the pain points for C2S for us, and there already is a concept of the server filling in partial activities from C2S for Create, so it doesn't seem out of line.
The only one this doesn't cover is removing someone from your followers. We're sending a Reject of the original Follow to communicate this (and using another bad server-side shortcut to find that Follow). I suppose a similar pattern would work, though
{
"actor": <you>,
"type": "Reject",
"object": {
"actor": <some-actor>,
"type": "Follow",
"object": <you>
}
}
No due date set.
No dependencies set.
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?