Skip to content

Commit

Permalink
Merge pull request #47 from City-of-Turku/feature/start-poll-add-thro…
Browse files Browse the repository at this point in the history
…ttling

Feature/start poll add throttling
  • Loading branch information
juuso-j committed Apr 9, 2024
2 parents 060f47b + 9aa45c0 commit 4c1bf66
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
6 changes: 5 additions & 1 deletion account/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from freezegun import freeze_time
from rest_framework.reverse import reverse

from account.api.views import ProfileViewSet
from account.models import MailingList, MailingListEmail, User
from profiles.models import PostalCode, PostalCodeResult

Expand Down Expand Up @@ -48,7 +49,10 @@ def test_unauthenticated_cannot_do_anything(api_client, users):
def test_mailing_list_unsubscribe_throttling(
api_client_with_custom_ip_address, mailing_list_emails
):
num_requests = 10
# Set number of requests to be made from the rate. The rate is stored as a string, e.g., rate = "10/day"
num_requests = int(
ProfileViewSet.unsubscribe.kwargs["throttle_classes"][0].rate.split("/")[0]
)
url = reverse("account:profiles-unsubscribe")
count = 0
while count < num_requests:
Expand Down
10 changes: 10 additions & 0 deletions profiles/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import django_filters
from rest_framework.exceptions import ValidationError
from rest_framework.throttling import AnonRateThrottle

from profiles.models import PostalCodeResult

Expand All @@ -15,6 +16,15 @@ def blur_count(count, threshold=5):
return count


class StartPollRateThrottle(AnonRateThrottle):
"""
The AnonRateThrottle will only ever throttle unauthenticated users.
The IP address of the incoming request is used to generate a unique key to throttle against.
"""

rate = "10/day"


class CustomValidationError(ValidationError):
# The detail field is shown also when DEBUG=False
# Ensures the error message is displayed to the user
Expand Down
3 changes: 2 additions & 1 deletion profiles/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
)
from profiles.utils import encrypt_text, generate_password, get_user_result

from .utils import PostalCodeResultFilter
from .utils import PostalCodeResultFilter, StartPollRateThrottle

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -185,6 +185,7 @@ def list(self, request, *args, **kwargs):
detail=False,
methods=["POST"],
permission_classes=[AllowAny],
throttle_classes=[StartPollRateThrottle],
)
def start_poll(self, request):
uuid4 = uuid.uuid4()
Expand Down
26 changes: 26 additions & 0 deletions profiles/tests/api/test_answer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import time

import pytest
from rest_framework.authtoken.models import Token
from rest_framework.reverse import reverse

from account.models import User
from profiles.api.views import QuestionViewSet
from profiles.models import Answer, Option, Question, SubQuestion


Expand All @@ -21,6 +24,29 @@ def test_start_poll(api_client):
assert User.objects.all().count() == 1


@pytest.mark.django_db
@pytest.mark.parametrize(
"ip_address",
[
("240.231.131.14"),
],
)
def test_start_poll_throttling(api_client_with_custom_ip_address):
# Set number of requests to be made from the rate. The rate is stored as a string, e.g., rate = "10/day"
num_requests = int(
QuestionViewSet.start_poll.kwargs["throttle_classes"][0].rate.split("/")[0]
)
url = reverse("profiles:question-start-poll")
count = 0
while count < num_requests:
response = api_client_with_custom_ip_address.post(url)
assert response.status_code == 200
count += 1
time.sleep(2)
response = api_client_with_custom_ip_address.post(url)
assert response.status_code == 429


@pytest.mark.django_db
def test_post_answer(api_client_authenticated, users, questions, options):
user = users.get(username="test1")
Expand Down

0 comments on commit 4c1bf66

Please sign in to comment.