Repository navigation
Routing Note and activity IDs under their Actor so they dereference - #324
Conversation
lisad
left a comment
There was a problem hiding this comment.
OK to merge but I suggested some refactors
| ) | ||
|
|
||
|
|
||
| def build_object_not_found_error(request=None): |
There was a problem hiding this comment.
This nested "build_x" approach looks very much like a functional approach for what could be simpler as an object-oriented approach - the method is a very thin wrapper. Error response is already an object concept in python requests, and already an inheritance-based one, so a specific "ObjectNotFound" error could be built on the generic "ResourceNotFound" error
Even cleaner (and requiring less utils) is raising custom exceptions and the custom exceptions get handled in post-view common handling that adds the error code.
Looking at this whole util file as more gets added to it and its purpose gets more clear, I am seeing what it does and guessing that it could be replaced with 10 lines even taking this basic functional approach.
- it adds more detailed codes on top of 400, 404, 500 with constants
- it adds full-sentence descriptions
- adds timestamps (redundant)
- adds new ID (generated once and does not correlate with anything)
Some of these jobs could be done with simple lookups (if the INSUFFICIENT_SCOPE constant is passed or the InsufficientScopeException is thrown, lookup the correct HTTP status code and explanation to return with the Response. ). Other jobs could be done in the Response object or exception handling. The new ID and timestamp jobs don't seem to be adding value.
There was a problem hiding this comment.
Yes, you're absolutely right with it. I'll iterate over it.
| @authentication_classes([OptionalOAuth2Authentication]) | ||
| @activitypub_content | ||
| @actor_required | ||
| def follow_activity_detail(request, pk, actor, object_pk): |
There was a problem hiding this comment.
These are once again very thin, repetitive wrappers
probably a single "serve_object" view could be called by multiple different
URL mappings, each one with a different object Type passing to it.
There was a problem hiding this comment.
I agreed and that's actually how I first wrote it with one view and each route passing its model and builder but I switched to four views to match the rest of api_urls.py. I'll deal with it in the follow-up PR
b8e9b33 to
ee71782
Compare
ee71782 to
c1bc153
Compare
This has been on my backlog for quite some time and its something I wanted to implement. I found a good reason to do it now while I am closing the source implementation.
Every Note and Activity we serve has an
idbut and fetching it returned404to everyone, including the owner.These are my reason to implement this now:
idnobody can fetch is in neither group.id.idinpreviously.Now Objects live under their Actor
I nested them because LOLA's section on hosting redirects for objects indicates that "If the original Actor identity is part of the URL of the Object that is no longer served, the source server can use that to look up the Actor and find the movedTo value."*
With plain numeric IDs the server "may need to keep a list of moved Objects and what Actor they were once associated with". LOLA requires a way for a user to delete their content while the Actor stays up with
movedTo. With the Actor in the URL, a deleted object's URL still names its Actor, so a later redirect from the source to the destination won't need an extra table. It also puts objects next to/api/actors/<pk>/outbox/and the other per-Actor endpoints.The URL alone doesn't prove ownership but the lookup does. Each view queries
model.objects.filter(pk=<object_pk>, actor=<actor>). Alice's Note requested under Bob's path is404, exactly as if it didn't exist.Access follows the object's own visibility:
200, the same JSON the collections serve403 actor_mismatch, as on every dual-mode endpoint200404 object_not_found404 object_not_found, the same answerA non-public object gives exactly the same answer as one that doesn't exist (ActivityPub §3.2: a server "which does not wish to disclose the existence of a private target MAY instead respond with a status code of 404 Not Found"). A missing Actor gives the existing
404 actor_not_found.Output for the same objects as above: