From df3f3d231ea871bd64893ee11e4223851f1b8c73 Mon Sep 17 00:00:00 2001 From: timehexon Date: Mon, 2 Feb 2026 18:04:53 +0000 Subject: [PATCH] Reject thread creation on nonexistent namespaces POST /api/v1/threads now returns 404 if the namespace doesn't already exist, instead of auto-creating it. Prevents phantom namespaces from accumulating when callers mistype the namespace name. get_or_create_namespace is still used for read-only endpoints (GET) where lazy creation is acceptable. --- remarkbox/api/views.py | 11 +++++++++-- remarkbox/tests/test_api_views.py | 13 +++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/remarkbox/api/views.py b/remarkbox/api/views.py index dfa973d..5149295 100644 --- a/remarkbox/api/views.py +++ b/remarkbox/api/views.py @@ -17,7 +17,11 @@ from remarkbox.models.user import ( is_user_name_valid, is_user_name_available, ) -from remarkbox.models.namespace import get_or_create_namespace, get_topsecret_namespaces +from remarkbox.models.namespace import ( + get_namespace_by_name, + get_or_create_namespace, + get_topsecret_namespaces, +) from remarkbox.models.node import Node from remarkbox.lib.mail import send_verification_digits_to_email from remarkbox.lib.notify import schedule_notifications @@ -464,7 +468,10 @@ def api_create_thread(request): ) } - namespace = get_or_create_namespace(request.dbsession, namespace_name) + namespace = get_namespace_by_name(request.dbsession, namespace_name) + if namespace is None: + request.response.status_code = 404 + return {"error": "namespace '{}' does not exist".format(namespace_name)} denied = check_namespace_api_access(request, namespace) if denied: diff --git a/remarkbox/tests/test_api_views.py b/remarkbox/tests/test_api_views.py index 31b8ac6..ec4bef9 100644 --- a/remarkbox/tests/test_api_views.py +++ b/remarkbox/tests/test_api_views.py @@ -119,6 +119,19 @@ class TestAPIAnonymousPosting(APIFunctionalTests): self.assertEqual(res.status_int, 400) self.assertIn("namespace", res.json["error"]) + def test_create_thread_nonexistent_namespace(self): + res = self.testapp.post_json( + "/api/v1/threads", + { + "namespace": "does-not-exist.example.com", + "title": "Test", + "data": "Should fail", + }, + expect_errors=True, + ) + self.assertEqual(res.status_int, 404) + self.assertIn("does not exist", res.json["error"]) + def test_create_thread_missing_title(self): res = self.testapp.post_json( "/api/v1/threads",