Throttling membership creation

remotes/origin/github-import
Alejandro Alonso 2017-01-04 08:42:57 +01:00
parent 8ca91f8d57
commit 83c445dd2f
5 changed files with 32 additions and 13 deletions

View File

@ -440,7 +440,7 @@ REST_FRAMEWORK = {
"user": None, "user": None,
"import-mode": None, "import-mode": None,
"import-dump-mode": "1/minute", "import-dump-mode": "1/minute",
"memberships": None, "create-memberships": None
}, },
"FILTER_BACKEND": "taiga.base.filters.FilterBackend", "FILTER_BACKEND": "taiga.base.filters.FilterBackend",
"EXCEPTION_HANDLER": "taiga.base.exceptions.exception_handler", "EXCEPTION_HANDLER": "taiga.base.exceptions.exception_handler",

View File

@ -33,5 +33,5 @@ REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = {
"user": None, "user": None,
"import-mode": None, "import-mode": None,
"import-dump-mode": None, "import-dump-mode": None,
"memberships": None, "create-memberships": None,
} }

View File

@ -153,11 +153,15 @@ class SimpleRateThrottle(BaseThrottle):
# throttle duration # throttle duration
while self.history and self.history[-1] <= self.now - self.duration: while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop() self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()
def throttle_success(self): if self.exceeded_throttling_restriction(request, view):
return self.throttle_failure()
return self.throttle_success(request, view)
def exceeded_throttling_restriction(self, request, view):
return len(self.history) >= self.num_requests
def throttle_success(self, request, view):
""" """
Inserts the current request's timestamp along with the key Inserts the current request's timestamp along with the key
into the cache. into the cache.

View File

@ -20,5 +20,20 @@ from taiga.base import throttling
class MembershipsRateThrottle(throttling.UserRateThrottle): class MembershipsRateThrottle(throttling.UserRateThrottle):
scope = "memberships" scope = "create-memberships"
throttled_methods = ["POST", "PUT"] throttled_methods = ["POST", "PUT"]
def exceeded_throttling_restriction(self, request, view):
self.created_memberships = 0
if view.action in ["create", "resend_invitation"]:
self.created_memberships = 1
elif view.action == "bulk_create":
self.created_memberships = len(request.DATA.get("bulk_memberships", []))
return len(self.history) + self.created_memberships > self.num_requests
def throttle_success(self, request, view):
for i in range(self.created_memberships):
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
return True

View File

@ -701,7 +701,7 @@ def test_api_create_bulk_members_max_pending_memberships(client, settings):
def test_create_memberhips_throttling(client, settings): def test_create_memberhips_throttling(client, settings):
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = "1/minute" settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = "1/minute"
membership = f.MembershipFactory(is_admin=True) membership = f.MembershipFactory(is_admin=True)
role = f.RoleFactory.create(project=membership.project) role = f.RoleFactory.create(project=membership.project)
@ -720,11 +720,11 @@ def test_create_memberhips_throttling(client, settings):
response = client.json.post(url, json.dumps(data)) response = client.json.post(url, json.dumps(data))
assert response.status_code == 429 assert response.status_code == 429
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = None settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = None
def test_api_resend_invitation_throttling(client, outbox, settings): def test_api_resend_invitation_throttling(client, outbox, settings):
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = "1/minute" settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = "1/minute"
invitation = f.create_invitation(user=None) invitation = f.create_invitation(user=None)
f.MembershipFactory(project=invitation.project, user=invitation.project.owner, is_admin=True) f.MembershipFactory(project=invitation.project, user=invitation.project.owner, is_admin=True)
@ -742,11 +742,11 @@ def test_api_resend_invitation_throttling(client, outbox, settings):
assert response.status_code == 429 assert response.status_code == 429
assert len(outbox) == 1 assert len(outbox) == 1
assert outbox[0].to == [invitation.email] assert outbox[0].to == [invitation.email]
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = None settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = None
def test_api_create_bulk_members_throttling(client, settings): def test_api_create_bulk_members_throttling(client, settings):
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = "1/minute" settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = "2/minute"
project = f.ProjectFactory() project = f.ProjectFactory()
john = f.UserFactory.create() john = f.UserFactory.create()
@ -781,4 +781,4 @@ def test_api_create_bulk_members_throttling(client, settings):
response = client.json.post(url, json.dumps(data)) response = client.json.post(url, json.dumps(data))
assert response.status_code == 429 assert response.status_code == 429
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = None settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = None