🔒️(backend) throttle the document mention endpoint

Add a dedicated "mention" throttle scope limiting calls
to the document mention endpoint to 30 requests per minute.

Signed-off-by: BOUKERFA Mohamed El Amine <boukerfa.ma@gmail.com>
This commit is contained in:
BOUKERFA Mohamed El Amine
2026-09-29 17:40:38 +02:00
committed by Manuel Raynaud
parent 28cb6b7251
commit c16a5887bd
3 changed files with 71 additions and 1 deletions
+6 -1
View File
@@ -1877,7 +1877,12 @@ class DocumentViewSet(
status=drf.status.HTTP_200_OK,
)
@drf.decorators.action(detail=True, methods=["post"], url_path="mention")
@drf.decorators.action(
detail=True,
methods=["post"],
url_path="mention",
throttle_scope="mention",
)
def mention(self, request, *args, **kwargs):
"""Mention a user on the document and notify them by email.
@@ -509,3 +509,63 @@ def test_api_documents_mention_soft_deleted_document():
assert response.status_code == 404
assert models.Mention.objects.exists() is False
def test_api_documents_mention_throttling(settings):
"""Mention requests should be throttled once the mention rate is exceeded."""
current_rate = settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["mention"]
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["mention"] = "3/minute"
user = factories.UserFactory()
document = factories.DocumentFactory(link_reach="restricted")
factories.UserDocumentAccessFactory(document=document, user=user, role="commenter")
mentioned_user = factories.UserFactory()
factories.UserDocumentAccessFactory(document=document, user=mentioned_user)
client = APIClient()
client.force_login(user)
payload = {"anchor_id": "block-1", "mentioned_user_id": str(mentioned_user.id)}
# The first three requests within the minute are allowed.
for _i in range(3):
response = client.post(f"/api/v1.0/documents/{document.id!s}/mention/", payload)
assert response.status_code == 201
# The fourth request is throttled.
response = client.post(f"/api/v1.0/documents/{document.id!s}/mention/", payload)
assert response.status_code == 429
# Restore original rate
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["mention"] = current_rate
def test_api_documents_mention_throttling_y_provider_exempted(settings):
"""
Collaboration-server requests bypass the mention throttle, just like other
document endpoints relying on the document throttle exemption.
"""
current_rate = settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["mention"]
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["mention"] = "3/minute"
settings.Y_PROVIDER_API_KEY = "test-y-provider-key"
user = factories.UserFactory()
document = factories.DocumentFactory(link_reach="restricted")
factories.UserDocumentAccessFactory(document=document, user=user, role="commenter")
mentioned_user = factories.UserFactory()
factories.UserDocumentAccessFactory(document=document, user=mentioned_user)
client = APIClient()
client.force_login(user)
payload = {"anchor_id": "block-1", "mentioned_user_id": str(mentioned_user.id)}
# More requests than the rate allows all succeed with the y-provider key.
for _i in range(5):
response = client.post(
f"/api/v1.0/documents/{document.id!s}/mention/",
payload,
HTTP_X_Y_PROVIDER_KEY="test-y-provider-key",
)
assert response.status_code == 201
# Restore original rate
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["mention"] = current_rate
+5
View File
@@ -486,6 +486,11 @@ class Base(Configuration):
environ_name="API_DOCUMENT_ASK_FOR_ACCESS_THROTTLE_RATE",
environ_prefix=None,
),
"mention": values.Value(
default="30/minute",
environ_name="API_MENTION_THROTTLE_RATE",
environ_prefix=None,
),
"config": values.Value(
default="30/minute",
environ_name="API_CONFIG_THROTTLE_RATE",