--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -11,7 +11,8 @@
from random import randint
from hashlib import sha256
from base64 import b64encode
-from datetime import datetime
+from datetime import datetime, timedelta
+import json
try:
import ldap
@@ -22,6 +23,7 @@
from tg import config, flash
from pylons import g, c
from webob import exc
+from bson.tz_util import FixedOffset
from ming.utils import LazyProperty
from ming.orm import state
@@ -334,6 +336,21 @@
'''
return []
+ def rate_limit(self, user, neighborhood):
+ '''Check the various config-defined project registration rate
+ limits, and if any are exceeded, raise ProjectRatelimitError.
+ '''
+ if security.has_access(neighborhood, 'admin', user=user)():
+ return
+ now = datetime.now().replace(tzinfo=FixedOffset(0, 'UTC'))
+ project_count = len(list(user.my_projects()))
+ rate_limits = json.loads(config.get('project.rate_limits', '{}'))
+ for rate, count in rate_limits.items():
+ user_age = now - user._id.generation_time
+ user_age = (user_age.microseconds + (user_age.seconds + user_age.days * 24 * 3600) * 10**6) / 10**6
+ if user_age < int(rate) and project_count >= count:
+ raise forge_exc.ProjectRatelimitError()
+
def register_neighborhood_project(self, neighborhood, users, allow_register=False):
from allura import model as M
shortname='--init--'
@@ -390,6 +407,8 @@
if nb_max_projects is not None and count >= nb_max_projects:
log.exception('Error registering project %s' % project_name)
raise forge_exc.ProjectOverlimitError()
+
+ self.rate_limit(user, neighborhood)
if not h.re_path_portion.match(shortname.replace('/', '')):
raise ValueError('Invalid project shortname: %s' % shortname)