diff --git a/passbook/admin/views/sources.py b/passbook/admin/views/sources.py index 3040b8323..3c409f794 100644 --- a/passbook/admin/views/sources.py +++ b/passbook/admin/views/sources.py @@ -10,6 +10,11 @@ from passbook.core.models import Source from passbook.lib.utils.reflection import path_to_class +def all_subclasses(cls): + """Recursively return all subclassess of cls""" + return set(cls.__subclasses__()).union( + [s for c in cls.__subclasses__() for s in all_subclasses(c)]) + class SourceListView(AdminRequiredMixin, ListView): """Show list of all sources""" @@ -18,7 +23,7 @@ class SourceListView(AdminRequiredMixin, ListView): def get_context_data(self, **kwargs): kwargs['types'] = { - x.__name__: x._meta.verbose_name for x in Source.__subclasses__()} + x.__name__: x._meta.verbose_name for x in all_subclasses(Source)} return super().get_context_data(**kwargs) def get_queryset(self): @@ -34,7 +39,7 @@ class SourceCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView): def get_form_class(self): source_type = self.request.GET.get('type') - model = next(x for x in Source.__subclasses__() if x.__name__ == source_type) + model = next(x for x in all_subclasses(Source) if x.__name__ == source_type) if not model: raise Http404 return path_to_class(model.form) diff --git a/passbook/oauth_client/forms.py b/passbook/oauth_client/forms.py index 1a582fcec..26121d2d6 100644 --- a/passbook/oauth_client/forms.py +++ b/passbook/oauth_client/forms.py @@ -1,6 +1,7 @@ """passbook oauth_client forms""" from django import forms +from django.utils.translation import gettext as _ from passbook.admin.forms.source import SOURCE_FORM_FIELDS from passbook.oauth_client.models import OAuthSource @@ -9,9 +10,97 @@ from passbook.oauth_client.models import OAuthSource class OAuthSourceForm(forms.ModelForm): """OAuthSource Form""" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if hasattr(self.Meta, 'overrides'): + for overide_field, overide_value in getattr(self.Meta, 'overrides').items(): + self.fields[overide_field].initial = overide_value + self.fields[overide_field].widget.attrs['readonly'] = 'readonly' + class Meta: model = OAuthSource fields = SOURCE_FORM_FIELDS + ['provider_type', 'request_token_url', 'authorization_url', 'access_token_url', 'profile_url', 'consumer_key', 'consumer_secret'] + widgets = { + 'name': forms.TextInput(), + 'consumer_key': forms.TextInput(), + 'consumer_secret': forms.TextInput(), + } + labels = { + 'request_token_url': _('Request Token URL'), + 'authorization_url': _('Authorization URL'), + 'access_token_url': _('Access Token URL'), + 'profile_url': _('Profile URL'), + } + + +class GitHubOAuthSourceForm(OAuthSourceForm): + """OAuth Source form with pre-determined URL for GitHub""" + + class Meta(OAuthSourceForm.Meta): + + overrides = { + 'provider_type': 'github', + 'request_token_url': '', + 'authorization_url': 'https://github.com/login/oauth/authorize', + 'access_token_url': 'https://github.com/login/oauth/access_token', + 'profile_url': ' https://api.github.com/user', + } + + +class TwitterOAuthSourceForm(OAuthSourceForm): + """OAuth Source form with pre-determined URL for Twitter""" + + class Meta(OAuthSourceForm.Meta): + + overrides = { + 'provider_type': 'twitter', + 'request_token_url': 'https://api.twitter.com/oauth/request_token', + 'authorization_url': 'https://api.twitter.com/oauth/authenticate', + 'access_token_url': 'https://api.twitter.com/oauth/access_token', + 'profile_url': ' https://api.twitter.com/1.1/account/verify_credentials.json', + } + + +class FacebookOAuthSourceForm(OAuthSourceForm): + """OAuth Source form with pre-determined URL for Facebook""" + + class Meta(OAuthSourceForm.Meta): + + overrides = { + 'provider_type': 'facebook', + 'request_token_url': '', + 'authorization_url': 'https://www.facebook.com/v2.8/dialog/oauth', + 'access_token_url': 'https://graph.facebook.com/v2.8/oauth/access_token', + 'profile_url': ' https://graph.facebook.com/v2.8/me?fields=name,email,short_name', + } + + +class DiscordOAuthSourceForm(OAuthSourceForm): + """OAuth Source form with pre-determined URL for Discord""" + + class Meta(OAuthSourceForm.Meta): + + overrides = { + 'provider_type': 'discord', + 'request_token_url': '', + 'authorization_url': 'https://discordapp.com/api/oauth2/authorize', + 'access_token_url': 'https://discordapp.com/api/oauth2/token', + 'profile_url': ' https://discordapp.com/api/users/@me', + } + + +class GoogleOAuthSourceForm(OAuthSourceForm): + """OAuth Source form with pre-determined URL for Google""" + + class Meta(OAuthSourceForm.Meta): + + overrides = { + 'provider_type': 'google', + 'request_token_url': '', + 'authorization_url': 'https://accounts.google.com/o/oauth2/auth', + 'access_token_url': 'https://accounts.google.com/o/oauth2/token', + 'profile_url': ' https://www.googleapis.com/oauth2/v1/userinfo', + } diff --git a/passbook/oauth_client/models.py b/passbook/oauth_client/models.py index 22d60ae7a..c53097e63 100644 --- a/passbook/oauth_client/models.py +++ b/passbook/oauth_client/models.py @@ -1,6 +1,7 @@ """OAuth Client models""" from django.db import models +from django.utils.translation import gettext as _ from passbook.core.models import Source, UserSourceConnection from passbook.oauth_client.clients import get_client @@ -17,14 +18,73 @@ class OAuthSource(Source): consumer_key = models.TextField() consumer_secret = models.TextField() - form = 'passbook.oauth_client.forms.OAuthSourceForm' + form = 'passbook.oauth_client.forms.GitHubOAuthSourceForm' class Meta: - verbose_name = 'OAuth Source' - verbose_name_plural = 'OAuth Sources' + verbose_name = _('Generic OAuth Source') + verbose_name_plural = _('Generic OAuth Sources') +class GitHubOAuthSource(OAuthSource): + """Abstract subclass of OAuthSource to specify GitHub Form""" + + form = 'passbook.oauth_client.forms.GitHubOAuthSourceForm' + + class Meta: + + abstract = True + verbose_name = _('GitHub OAuth Source') + verbose_name_plural = _('GitHub OAuth Sources') + + +class TwitterOAuthSource(OAuthSource): + """Abstract subclass of OAuthSource to specify Twitter Form""" + + form = 'passbook.oauth_client.forms.TwitterOAuthSourceForm' + + class Meta: + + abstract = True + verbose_name = _('Twitter OAuth Source') + verbose_name_plural = _('Twitter OAuth Sources') + + +class FacebookOAuthSource(OAuthSource): + """Abstract subclass of OAuthSource to specify Facebook Form""" + + form = 'passbook.oauth_client.forms.FacebookOAuthSourceForm' + + class Meta: + + abstract = True + verbose_name = _('Facebook OAuth Source') + verbose_name_plural = _('Facebook OAuth Sources') + + +class DiscordOAuthSource(OAuthSource): + """Abstract subclass of OAuthSource to specify Discord Form""" + + form = 'passbook.oauth_client.forms.DiscordOAuthSourceForm' + + class Meta: + + abstract = True + verbose_name = _('Discord OAuth Source') + verbose_name_plural = _('Discord OAuth Sources') + + +class GoogleOAuthSource(OAuthSource): + """Abstract subclass of OAuthSource to specify Google Form""" + + form = 'passbook.oauth_client.forms.GoogleOAuthSourceForm' + + class Meta: + + abstract = True + verbose_name = _('Google OAuth Source') + verbose_name_plural = _('Google OAuth Sources') + class UserOAuthSourceConnection(UserSourceConnection): """Authorized remote OAuth provider.""" @@ -42,5 +102,5 @@ class UserOAuthSourceConnection(UserSourceConnection): class Meta: - verbose_name = 'User OAuth Source Connection' - verbose_name_plural = 'User OAuth Source Connections' + verbose_name = _('User OAuth Source Connection') + verbose_name_plural = _('User OAuth Source Connections')