diff --git a/api/views/__init__.py b/api/views/__init__.py index e69de29b..74f6b1d2 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -0,0 +1,10 @@ +from django.http import Http404 +from django.shortcuts import get_object_or_404 as _get_object_or_404 + + +def get_object_or_404(*args, **kwargs): + """Wrapper that returns 404 for invalid PK types (e.g. non-numeric IDs).""" + try: + return _get_object_or_404(*args, **kwargs) + except (ValueError, TypeError): + raise Http404 diff --git a/api/views/accounts.py b/api/views/accounts.py index 0dffdbb5..d1816a64 100644 --- a/api/views/accounts.py +++ b/api/views/accounts.py @@ -5,7 +5,7 @@ from core.models import Config from django.core.files import File from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import ApiResponse, QueryOrBody, api_view from users.services import IdentityService from users.shortcuts import by_handle_or_404 diff --git a/api/views/announcements.py b/api/views/announcements.py index 27f1ab9a..d9a208a1 100644 --- a/api/views/announcements.py +++ b/api/views/announcements.py @@ -1,4 +1,4 @@ -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import api_view from api import schemas diff --git a/api/views/conversations.py b/api/views/conversations.py index 2aa98fee..a31b7f91 100644 --- a/api/views/conversations.py +++ b/api/views/conversations.py @@ -1,5 +1,5 @@ from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from activities.models.conversation import Conversation, ConversationMembership from activities.services import TimelineService diff --git a/api/views/follow_requests.py b/api/views/follow_requests.py index cf54b927..1013dcf9 100644 --- a/api/views/follow_requests.py +++ b/api/views/follow_requests.py @@ -1,5 +1,5 @@ from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import api_view from api import schemas diff --git a/api/views/lists.py b/api/views/lists.py index b01d5a94..8fb6bec8 100644 --- a/api/views/lists.py +++ b/api/views/lists.py @@ -1,7 +1,7 @@ from typing import Literal from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import Schema, api_view from api import schemas diff --git a/api/views/media.py b/api/views/media.py index 32bc6e18..44ccf429 100644 --- a/api/views/media.py +++ b/api/views/media.py @@ -1,7 +1,7 @@ import mimetypes from django.core.files import File -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import ApiError, QueryOrBody, api_view from activities.models import PostAttachment, PostAttachmentStates diff --git a/api/views/notifications.py b/api/views/notifications.py index 5bdda95f..2c53ec5f 100644 --- a/api/views/notifications.py +++ b/api/views/notifications.py @@ -3,7 +3,7 @@ from activities.models import PostInteraction, TimelineEvent from activities.services import TimelineService from django.http import Http404, HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import ApiResponse, QueryOrBody, api_view from api import schemas diff --git a/api/views/polls.py b/api/views/polls.py index 2b47f72f..04c5a319 100644 --- a/api/views/polls.py +++ b/api/views/polls.py @@ -1,5 +1,5 @@ from django.http import Http404 -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from hatchway import api_view, QueryOrBody from activities.models import Post, PostInteraction diff --git a/api/views/push.py b/api/views/push.py index 2fc5f7ee..52fffce2 100644 --- a/api/views/push.py +++ b/api/views/push.py @@ -1,6 +1,6 @@ from django.conf import settings from django.http import Http404 -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from api import schemas from api.decorators import scope_required diff --git a/api/views/report.py b/api/views/report.py index 14fe39a4..6bdc930d 100644 --- a/api/views/report.py +++ b/api/views/report.py @@ -1,4 +1,4 @@ -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from activities.models import Post from api import schemas diff --git a/api/views/statuses.py b/api/views/statuses.py index e1092c22..4d11157d 100644 --- a/api/views/statuses.py +++ b/api/views/statuses.py @@ -4,7 +4,7 @@ from django.db.models import Q from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from django.utils import timezone from pydantic import ConfigDict diff --git a/api/views/tags.py b/api/views/tags.py index 2b81ba60..5b6a8bf9 100644 --- a/api/views/tags.py +++ b/api/views/tags.py @@ -1,7 +1,7 @@ import datetime from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from django.utils import timezone from activities.models import FanOut, Hashtag, Post diff --git a/api/views/timelines.py b/api/views/timelines.py index 008857ea..4a340f1e 100644 --- a/api/views/timelines.py +++ b/api/views/timelines.py @@ -1,5 +1,5 @@ from django.http import HttpRequest -from django.shortcuts import get_object_or_404 +from api.views import get_object_or_404 from activities.models import Post, TimelineEvent from activities.services import TimelineService diff --git a/core/signatures.py b/core/signatures.py index 2e01927a..799cb5f7 100644 --- a/core/signatures.py +++ b/core/signatures.py @@ -343,7 +343,7 @@ def signed_request( method == "post" and response.status_code >= 400 and response.status_code < 500 - and response.status_code != 404 + and response.status_code not in [404, 410] ): raise ValueError( f"POST error to {uri}: {response.status_code} {response.content!r}" diff --git a/users/models/block.py b/users/models/block.py index b452a958..99ab3f98 100644 --- a/users/models/block.py +++ b/users/models/block.py @@ -301,13 +301,11 @@ def handle_undo_ap(cls, data): """ Handles an incoming Block Undo """ - # Resolve source and target and see if a Follow exists (it hopefully does) try: block = cls.by_ap(data["object"]) - except KeyError: - raise ValueError("No Block locally for incoming Undo", data) + except (KeyError, cls.DoesNotExist): + return # Check the block's source is the actor if data["actor"] != block.source.actor_uri: raise ValueError("Undo actor does not match its Block object", data) - # Delete the follow block.delete() diff --git a/users/models/domain.py b/users/models/domain.py index 71dbdf97..643ad086 100644 --- a/users/models/domain.py +++ b/users/models/domain.py @@ -231,7 +231,7 @@ def fetch_nodeinfo(self) -> NodeInfo | None: ): nodeinfo20_url = link.get("href", nodeinfo20_url) break - except (json.JSONDecodeError, AttributeError): + except (json.JSONDecodeError, AttributeError, UnicodeDecodeError): pass try: