Skip to content

Commit

Permalink
Merge pull request #909 from taigaio/throttling-memberships-creation
Browse files Browse the repository at this point in the history
Throttling membership creation
  • Loading branch information
jespino committed Jan 4, 2017
2 parents 8ca91f8 + 83c445d commit 3601ee4
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 12 deletions.
2 changes: 1 addition & 1 deletion settings/common.py
Expand Up @@ -440,7 +440,7 @@
"user": None,
"import-mode": None,
"import-dump-mode": "1/minute",
"memberships": None,
"create-memberships": None
},
"FILTER_BACKEND": "taiga.base.filters.FilterBackend",
"EXCEPTION_HANDLER": "taiga.base.exceptions.exception_handler",
Expand Down
2 changes: 1 addition & 1 deletion settings/testing.py
Expand Up @@ -33,5 +33,5 @@
"user": None,
"import-mode": None,
"import-dump-mode": None,
"memberships": None,
"create-memberships": None,
}
10 changes: 7 additions & 3 deletions taiga/base/api/throttling.py
Expand Up @@ -153,11 +153,15 @@ def allow_request(self, request, view):
# throttle duration
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:

if self.exceeded_throttling_restriction(request, view):
return self.throttle_failure()
return self.throttle_success()
return self.throttle_success(request, view)

def exceeded_throttling_restriction(self, request, view):
return len(self.history) >= self.num_requests

def throttle_success(self):
def throttle_success(self, request, view):
"""
Inserts the current request's timestamp along with the key
into the cache.
Expand Down
17 changes: 16 additions & 1 deletion taiga/projects/throttling.py
Expand Up @@ -20,5 +20,20 @@


class MembershipsRateThrottle(throttling.UserRateThrottle):
scope = "memberships"
scope = "create-memberships"
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
12 changes: 6 additions & 6 deletions tests/integration/test_memberships.py
Expand Up @@ -701,7 +701,7 @@ def test_api_create_bulk_members_max_pending_memberships(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)
role = f.RoleFactory.create(project=membership.project)
Expand All @@ -720,11 +720,11 @@ def test_create_memberhips_throttling(client, settings):
response = client.json.post(url, json.dumps(data))

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):
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)
f.MembershipFactory(project=invitation.project, user=invitation.project.owner, is_admin=True)
Expand All @@ -742,11 +742,11 @@ def test_api_resend_invitation_throttling(client, outbox, settings):
assert response.status_code == 429
assert len(outbox) == 1
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):
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = "1/minute"
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = "2/minute"

project = f.ProjectFactory()
john = f.UserFactory.create()
Expand Down Expand Up @@ -781,4 +781,4 @@ def test_api_create_bulk_members_throttling(client, settings):
response = client.json.post(url, json.dumps(data))

assert response.status_code == 429
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["memberships"] = None
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["create-memberships"] = None

0 comments on commit 3601ee4

Please sign in to comment.