[Backport] Throttling membership creation
parent
ed9ddf9aa9
commit
ec049521e4
|
@ -424,7 +424,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",
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -606,7 +606,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)
|
||||||
|
@ -625,11 +625,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)
|
||||||
|
@ -647,11 +647,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()
|
||||||
|
@ -686,4 +686,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
|
||||||
|
|
Loading…
Reference in New Issue