diff --git a/e2e/test_provider_oauth.py b/e2e/test_provider_oauth.py index 6b40bbfc7..8733a15e7 100644 --- a/e2e/test_provider_oauth.py +++ b/e2e/test_provider_oauth.py @@ -103,9 +103,9 @@ class TestProviderOAuth(SeleniumTestCase): USER().username, ) self.assertEqual( - self.driver.find_element( - By.CSS_SELECTOR, "input[name=name]" - ).get_attribute("value"), + self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute( + "value" + ), USER().username, ) self.assertEqual( @@ -172,9 +172,9 @@ class TestProviderOAuth(SeleniumTestCase): USER().username, ) self.assertEqual( - self.driver.find_element( - By.CSS_SELECTOR, "input[name=name]" - ).get_attribute("value"), + self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute( + "value" + ), USER().username, ) self.assertEqual( diff --git a/e2e/test_provider_oidc.py b/e2e/test_provider_oidc.py index c9ae3524c..779a048bf 100644 --- a/e2e/test_provider_oidc.py +++ b/e2e/test_provider_oidc.py @@ -153,9 +153,9 @@ class TestProviderOIDC(SeleniumTestCase): USER().name, ) self.assertEqual( - self.driver.find_element( - By.CSS_SELECTOR, "input[name=name]" - ).get_attribute("value"), + self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute( + "value" + ), USER().name, ) self.assertEqual( @@ -232,9 +232,9 @@ class TestProviderOIDC(SeleniumTestCase): USER().name, ) self.assertEqual( - self.driver.find_element( - By.CSS_SELECTOR, "input[name=name]" - ).get_attribute("value"), + self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute( + "value" + ), USER().name, ) self.assertEqual( diff --git a/passbook/core/models.py b/passbook/core/models.py index 3febb463a..ad91b616c 100644 --- a/passbook/core/models.py +++ b/passbook/core/models.py @@ -1,12 +1,13 @@ """passbook core models""" from datetime import timedelta -from typing import Any, Optional +from typing import Any, Optional, Type from uuid import uuid4 from django.contrib.auth.models import AbstractUser from django.contrib.postgres.fields import JSONField from django.db import models from django.db.models import Q, QuerySet +from django.forms import ModelForm from django.http import HttpRequest from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ @@ -162,10 +163,12 @@ class Source(PolicyBindingModel): related_name="source_enrollment", ) - form = "" # ModelForm-based class ued to create/edit instance - objects = InheritanceManager() + def form(self) -> Type[ModelForm]: + """Return Form class used to edit this object""" + raise NotImplementedError + @property def ui_login_button(self) -> Optional[UILoginButton]: """If source uses a http-based flow, return UI Information about the login @@ -261,9 +264,12 @@ class PropertyMapping(models.Model): name = models.TextField() expression = models.TextField() - form = "" objects = InheritanceManager() + def form(self) -> Type[ModelForm]: + """Return Form class used to edit this object""" + raise NotImplementedError + def evaluate( self, user: Optional[User], request: Optional[HttpRequest], **kwargs ) -> Any: diff --git a/passbook/sources/ldap/models.py b/passbook/sources/ldap/models.py index 0de975870..b4581d11d 100644 --- a/passbook/sources/ldap/models.py +++ b/passbook/sources/ldap/models.py @@ -1,8 +1,9 @@ """passbook LDAP Models""" -from typing import Optional +from typing import Optional, Type from django.core.validators import URLValidator from django.db import models +from django.forms import ModelForm from django.utils.translation import gettext_lazy as _ from ldap3 import Connection, Server @@ -53,7 +54,10 @@ class LDAPSource(Source): Group, blank=True, null=True, default=None, on_delete=models.SET_DEFAULT ) - form = "passbook.sources.ldap.forms.LDAPSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.ldap.forms import LDAPSourceForm + + return LDAPSourceForm _connection: Optional[Connection] = None diff --git a/passbook/sources/oauth/models.py b/passbook/sources/oauth/models.py index 95262f32f..ff97d84f2 100644 --- a/passbook/sources/oauth/models.py +++ b/passbook/sources/oauth/models.py @@ -1,7 +1,8 @@ """OAuth Client models""" -from typing import Optional +from typing import Optional, Type from django.db import models +from django.forms import ModelForm from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ @@ -40,7 +41,10 @@ class OAuthSource(Source): consumer_key = models.TextField() consumer_secret = models.TextField() - form = "passbook.sources.oauth.forms.OAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import OAuthSourceForm + + return OAuthSourceForm @property def ui_login_button(self) -> UILoginButton: @@ -80,7 +84,10 @@ class OAuthSource(Source): class GitHubOAuthSource(OAuthSource): """Social Login using GitHub.com or a GitHub-Enterprise Instance.""" - form = "passbook.sources.oauth.forms.GitHubOAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import GitHubOAuthSourceForm + + return GitHubOAuthSourceForm class Meta: @@ -92,7 +99,9 @@ class GitHubOAuthSource(OAuthSource): # class TwitterOAuthSource(OAuthSource): # """Social Login using Twitter.com""" -# form = "passbook.sources.oauth.forms.TwitterOAuthSourceForm" +# def form(self) -> Type[ModelForm]: +# from passbook.sources.oauth.forms import TwitterOAuthSourceForm +# return TwitterOAuthSourceForm # class Meta: @@ -104,7 +113,10 @@ class GitHubOAuthSource(OAuthSource): class FacebookOAuthSource(OAuthSource): """Social Login using Facebook.com.""" - form = "passbook.sources.oauth.forms.FacebookOAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import FacebookOAuthSourceForm + + return FacebookOAuthSourceForm class Meta: @@ -116,7 +128,10 @@ class FacebookOAuthSource(OAuthSource): class DiscordOAuthSource(OAuthSource): """Social Login using Discord.""" - form = "passbook.sources.oauth.forms.DiscordOAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import DiscordOAuthSourceForm + + return DiscordOAuthSourceForm class Meta: @@ -128,7 +143,10 @@ class DiscordOAuthSource(OAuthSource): class GoogleOAuthSource(OAuthSource): """Social Login using Google or Gsuite.""" - form = "passbook.sources.oauth.forms.GoogleOAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import GoogleOAuthSourceForm + + return GoogleOAuthSourceForm class Meta: @@ -140,7 +158,10 @@ class GoogleOAuthSource(OAuthSource): class AzureADOAuthSource(OAuthSource): """Social Login using Azure AD.""" - form = "passbook.sources.oauth.forms.AzureADOAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import AzureADOAuthSourceForm + + return AzureADOAuthSourceForm class Meta: @@ -152,7 +173,10 @@ class AzureADOAuthSource(OAuthSource): class OpenIDOAuthSource(OAuthSource): """Login using a Generic OpenID-Connect compliant provider.""" - form = "passbook.sources.oauth.forms.OAuthSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.oauth.forms import OAuthSourceForm + + return OAuthSourceForm class Meta: diff --git a/passbook/sources/saml/models.py b/passbook/sources/saml/models.py index 33e1b3da9..9a76a83d8 100644 --- a/passbook/sources/saml/models.py +++ b/passbook/sources/saml/models.py @@ -1,5 +1,8 @@ """saml sp models""" +from typing import Type + from django.db import models +from django.forms import ModelForm from django.http import HttpRequest from django.shortcuts import reverse from django.urls import reverse_lazy @@ -93,7 +96,10 @@ class SAMLSource(Source): on_delete=models.PROTECT, ) - form = "passbook.sources.saml.forms.SAMLSourceForm" + def form(self) -> Type[ModelForm]: + from passbook.sources.saml.forms import SAMLSourceForm + + return SAMLSourceForm def get_issuer(self, request: HttpRequest) -> str: """Get Source's Issuer, falling back to our Metadata URL if none is set"""