diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index 42dc8195a..627f27b91 100755 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -2896,7 +2896,12 @@ class ApiController(RedditController, OAuth2ResourceController): if client.has_developer(account): form.set_html('.status', _('already added')) return - client.add_developer(account) + try: + client.add_developer(account) + except OverflowError: + form.set_html('.status', _('too many developers')) + return + form.set_html('.status', _('developer added')) apps = PrefApps([], [client]) (jquery('#app-developer-%s input[name="name"]' % client._id).val('') diff --git a/r2/r2/models/token.py b/r2/r2/models/token.py index b33cf0216..eb4a28564 100644 --- a/r2/r2/models/token.py +++ b/r2/r2/models/token.py @@ -95,6 +95,7 @@ class ConsumableToken(Token): class OAuth2Client(Token): """A client registered for OAuth2 access""" + max_developers = 20 token_size = 10 client_secret_size = 20 _defaults = dict(name="", @@ -115,14 +116,23 @@ class OAuth2Client(Token): kwargs["secret"] = generate_token(cls.client_secret_size) return super(OAuth2Client, cls)._new(**kwargs) + @property + def _developer_ids(self): + for k, v in self._t.iteritems(): + if k.startswith(self._developer_colname_prefix) and v: + try: + yield int(k[len(self._developer_colname_prefix):], 36) + except ValueError: + pass + @property def _developers(self): """Returns a list of users who are developers of this client.""" devs = [] - for k in [ k for k, v in self._t.iteritems() if k.startswith(self._developer_colname_prefix) and v ]: + for dev_id in self._developer_ids: try: - dev = Account._byID36(k[len(self._developer_colname_prefix):]) + dev = Account._byID(dev_id) if dev._deleted or dev._spam: raise NotFound except NotFound: @@ -149,10 +159,13 @@ class OAuth2Client(Token): else: return getattr(self, self._developer_colname(account), False) - def add_developer(self, account): + def add_developer(self, account, force=False): """Grants developer access to the supplied Account.""" - if not getattr(self, self._developer_colname(account), False): + dev_ids = set(self._developer_ids) + if account._id not in dev_ids: + if not force and len(dev_ids) >= self.max_developers: + raise OverflowError('max developers reached') setattr(self, self._developer_colname(account), True) self._commit() diff --git a/r2/r2/templates/prefapps.html b/r2/r2/templates/prefapps.html index c1796fbff..307771a89 100644 --- a/r2/r2/templates/prefapps.html +++ b/r2/r2/templates/prefapps.html @@ -13,7 +13,7 @@ %if devs:
Developers: - %for i, dev in enumerate(devs): + %for i, dev in enumerate(sorted(devs, key=lambda d: d.name)): %if i: %if i == len(devs) - 1: and @@ -126,7 +126,7 @@ ${_("developers")}