diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index c5f67e0c6..c4d0451bc 100755 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -662,7 +662,9 @@ class PrefApps(Templated): """Preference form for managing authorized third-party applications.""" def __init__(self, my_apps, developed_apps): - self.my_apps = my_apps + from r2.controllers.oauth2 import scope_info + self.my_apps = [(app, [scope_info[scope] for scope in scopes]) + for app, scopes in my_apps] self.developed_apps = developed_apps super(PrefApps, self).__init__() diff --git a/r2/r2/models/token.py b/r2/r2/models/token.py index 5977291a5..0af9b01fc 100644 --- a/r2/r2/models/token.py +++ b/r2/r2/models/token.py @@ -200,14 +200,18 @@ class OAuth2Client(Token): @classmethod def _by_user(cls, account): - """Returns a (possibly empty) list of clients for which Account has outstanding access tokens.""" + """Returns a (possibly empty) list of client-scope pairs for which Account has outstanding access tokens.""" client_ids = set() + client_id_to_scope = {} for token in OAuth2AccessToken._by_user(account): if token.check_valid(): - client_ids.add(token.client_id) + client_id_to_scope.setdefault(token.client_id, set()).update( + token.scope_list) - return cls._byID(client_ids).values() + clients = cls._byID(client_id_to_scope.keys()) + return [(client, list(client_id_to_scope.get(client_id, []))) + for client_id, client in clients.iteritems()] def revoke(self, account): """Revoke all of the outstanding OAuth2AccessTokens associated with this client and user Account.""" @@ -271,8 +275,7 @@ class OAuth2AccessToken(Token): _connection_pool = "main" @classmethod - def _new(cls, client_id, user_id, scope_list): - scope = ','.join(scope_list) + def _new(cls, client_id, user_id, scope): return super(OAuth2AccessToken, cls)._new( client_id=client_id, user_id=user_id, diff --git a/r2/r2/public/static/css/reddit.css b/r2/r2/public/static/css/reddit.css index ea5f4dcb5..b57e489f5 100755 --- a/r2/r2/public/static/css/reddit.css +++ b/r2/r2/public/static/css/reddit.css @@ -5887,6 +5887,17 @@ tr.gold-accent + tr > td { vertical-align: middle; } +.app-permissions li { position: relative; } +.app-scope { + display: none; + position: absolute; + top: 1ex; + left: 3ex; + border: 1px solid black; + background: #fffdcc; + z-index: 1; +} + .app-description { display: inline-block; font-size: small; diff --git a/r2/r2/public/static/js/apps.js b/r2/r2/public/static/js/apps.js index 4f470a6ce..144b95d06 100644 --- a/r2/r2/public/static/js/apps.js +++ b/r2/r2/public/static/js/apps.js @@ -1,20 +1,32 @@ r.apps = { init: function() { + $(".authorized-app") + .delegate(".app-permissions li", "mouseover mouseout", + function(e) { + if (e.type == "mouseover") { + $(this).find(".app-scope").show(); + } else { + $(this).find(".app-scope").hide(); + } + }) + ; + $("#developed-apps") .delegate(".edit-app-button", "click", function() { - $(this).toggleClass("collapsed").closest(".developed-app") - .removeClass('collapsed') - .find(".app-developers").remove().end() - .find(".edit-app") - .slideToggle().removeClass('collapsed').end(); + $(this).toggleClass("collapsed").closest(".developed-app") + .removeClass('collapsed') + .find(".app-developers").remove().end() + .find(".edit-app") + .slideToggle().removeClass('collapsed').end(); }) .delegate(".edit-app-icon-button", "click", function() { - $(this).toggleClass("collapsed") - .closest(".developed-app") - .find(".ajax-upload-form").show(); - }); + $(this).toggleClass("collapsed") + .closest(".developed-app") + .find(".ajax-upload-form").show(); + }) + ; $("#create-app-button").click( function() { diff --git a/r2/r2/templates/prefapps.html b/r2/r2/templates/prefapps.html index 7daa7a2ba..3113f8caa 100644 --- a/r2/r2/templates/prefapps.html +++ b/r2/r2/templates/prefapps.html @@ -164,7 +164,7 @@ %if thing.my_apps:

${_("authorized applications")}

- %for app in thing.my_apps: + %for app, scopes in thing.my_apps:
${icon(app)}
@@ -175,6 +175,14 @@ ${app.name} %endif +
${app.description}
${developers(app)}