Skip to content

Commit

Permalink
feat: sites is no longer required
Browse files Browse the repository at this point in the history
  • Loading branch information
pennersr committed Dec 17, 2021
1 parent a7327a0 commit 16ee545
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 34 deletions.
7 changes: 7 additions & 0 deletions ChangeLog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ Note worthy changes
``allauth.account.views.PasswordResetFromKeyView`` which allows specifying
a token parameter displayed as a component of password reset URLs.

- It is now possible to use allauth without having `sites` installed. Whether or
not sites is used affects the data models. For example, the social app model
uses a many-to-many pointing to the sites model if the `sites` app is
installed. Therefore, enabling or disabling `sites` is not something you can
do on the fly.



Backwards incompatible changes
------------------------------
Expand Down
2 changes: 1 addition & 1 deletion allauth/account/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ def respond_email_verification_sent(self, request, user):
def _get_login_attempts_cache_key(self, request, **credentials):
site = get_current_site(request)
login = credentials.get("email", credentials.get("username", "")).lower()
return "{site_id}:{login}".format(site_id=site.pk, login=login)
return "{site}:{login}".format(site=site.domain, login=login)

def _delete_login_attempts_cached_email(self, request, **credentials):
if app_settings.LOGIN_ATTEMPTS_LIMIT:
Expand Down
25 changes: 17 additions & 8 deletions allauth/account/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from django.contrib.messages.api import get_messages
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.sites.models import Site
from django.core import mail, validators
from django.core.exceptions import ValidationError
from django.db import models
Expand All @@ -22,6 +21,7 @@
from django.urls import reverse
from django.utils.timezone import now

import allauth.app_settings
from allauth.account.forms import BaseSignupForm, ResetPasswordForm, SignupForm
from allauth.account.models import (
EmailAddress,
Expand Down Expand Up @@ -66,7 +66,10 @@ def setUp(self):
from ..socialaccount.models import SocialApp

sa = SocialApp.objects.create(name="testfb", provider="facebook")
sa.sites.add(Site.objects.get_current())
if allauth.app_settings.SITES_ENABLED:
from django.contrib.sites.models import Site

sa.sites.add(Site.objects.get_current())

@override_settings(
ACCOUNT_AUTHENTICATION_METHOD=app_settings.AuthenticationMethod.USERNAME_EMAIL
Expand Down Expand Up @@ -544,13 +547,17 @@ def test_email_verification_mandatory(self):
)

def test_email_escaping(self):
site = Site.objects.get_current()
site.name = '<enc&"test>'
site.save()
site_name = "testserver"
if allauth.app_settings.SITES_ENABLED:
from django.contrib.sites.models import Site

site = Site.objects.get_current()
site.name = site_name = '<enc&"test>'
site.save()
u = get_user_model().objects.create(username="test", email="user@example.com")
request = RequestFactory().get("/")
EmailAddress.objects.add_email(request, u, u.email, confirm=True)
self.assertTrue(mail.outbox[0].subject[1:].startswith(site.name))
self.assertTrue(mail.outbox[0].subject[1:].startswith(site_name))

@override_settings(
ACCOUNT_EMAIL_VERIFICATION=app_settings.EmailVerificationMethod.OPTIONAL
Expand Down Expand Up @@ -925,7 +932,8 @@ def test_email_confirmation_hmac(self):
user=user, email="a@b.com", verified=False, primary=True
)
confirmation = EmailConfirmationHMAC(email)
confirmation.send()
request = RequestFactory().get("/")
confirmation.send(request=request)
self.assertEqual(len(mail.outbox), 1)
self.client.post(reverse("account_confirm_email", args=[confirmation.key]))
email = EmailAddress.objects.get(pk=email.pk)
Expand All @@ -941,7 +949,8 @@ def test_email_confirmation_hmac_timeout(self):
user=user, email="a@b.com", verified=False, primary=True
)
confirmation = EmailConfirmationHMAC(email)
confirmation.send()
request = RequestFactory().get("/")
confirmation.send(request=request)
self.assertEqual(len(mail.outbox), 1)
self.client.post(reverse("account_confirm_email", args=[confirmation.key]))
email = EmailAddress.objects.get(pk=email.pk)
Expand Down
1 change: 1 addition & 0 deletions allauth/app_settings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.conf import settings


SITES_ENABLED = "django.contrib.sites" in settings.INSTALLED_APPS
SOCIALACCOUNT_ENABLED = "allauth.socialaccount" in settings.INSTALLED_APPS

LOGIN_REDIRECT_URL = getattr(settings, "LOGIN_REDIRECT_URL", "/")
Expand Down
3 changes: 2 additions & 1 deletion allauth/socialaccount/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django import forms
from django.contrib import admin

from allauth import app_settings
from allauth.account.adapter import get_adapter

from .models import SocialAccount, SocialApp, SocialToken
Expand All @@ -23,7 +24,7 @@ class SocialAppAdmin(admin.ModelAdmin):
"name",
"provider",
)
filter_horizontal = ("sites",)
filter_horizontal = ("sites",) if app_settings.SITES_ENABLED else ()


class SocialAccountAdmin(admin.ModelAdmin):
Expand Down
25 changes: 19 additions & 6 deletions allauth/socialaccount/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@
from django.db import migrations, models

import allauth.socialaccount.fields
from allauth import app_settings
from allauth.socialaccount.providers import registry


class Migration(migrations.Migration):

dependencies = [
("sites", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
dependencies = (
[
("sites", "0001_initial"),
]
if app_settings.SITES_ENABLED
else []
+ [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
)

operations = [
migrations.CreateModel(
Expand Down Expand Up @@ -118,8 +125,14 @@ class Migration(migrations.Migration):
blank=True,
),
),
("sites", models.ManyToManyField(to="sites.Site", blank=True)),
],
]
+ (
[
("sites", models.ManyToManyField(to="sites.Site", blank=True)),
]
if app_settings.SITES_ENABLED
else []
),
options={
"verbose_name": "social application",
"verbose_name_plural": "social applications",
Expand Down
19 changes: 11 additions & 8 deletions allauth/socialaccount/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import absolute_import

from django.contrib.auth import authenticate
from django.contrib.sites.models import Site
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import PermissionDenied
from django.db import models
Expand All @@ -28,8 +27,11 @@ def get_current(self, provider, request=None):
request._socialapp_cache = cache
app = cache.get(provider)
if not app:
site = get_current_site(request)
app = self.get(sites__id=site.id, provider=provider)
if allauth.app_settings.SITES_ENABLED:
site = get_current_site(request)
app = self.get(sites__id=site.id, provider=provider)
else:
app = self.get(provider=provider)
cache[provider] = app
return app

Expand Down Expand Up @@ -57,11 +59,12 @@ class SocialApp(models.Model):
key = models.CharField(
verbose_name=_("key"), max_length=191, blank=True, help_text=_("Key")
)
# Most apps can be used across multiple domains, therefore we use
# a ManyToManyField. Note that Facebook requires an app per domain
# (unless the domains share a common base name).
# blank=True allows for disabling apps without removing them
sites = models.ManyToManyField(Site, blank=True)
if allauth.app_settings.SITES_ENABLED:
# Most apps can be used across multiple domains, therefore we use
# a ManyToManyField. Note that Facebook requires an app per domain
# (unless the domains share a common base name).
# blank=True allows for disabling apps without removing them
sites = models.ManyToManyField("sites.Site", blank=True)

# We want to move away from storing secrets in the database. So, we're
# putting a halt towards adding more fields for additional secrets, such as
Expand Down
7 changes: 5 additions & 2 deletions allauth/socialaccount/providers/draugiem/tests.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from hashlib import md5

from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.urls import reverse
from django.utils.http import urlencode

from allauth import app_settings
from allauth.socialaccount import providers
from allauth.socialaccount.models import SocialApp, SocialToken
from allauth.tests import Mock, TestCase, patch
Expand All @@ -30,7 +30,10 @@ def setUp(self):
key=self.provider.id,
secret="dummy",
)
app.sites.add(Site.objects.get_current())
if app_settings.SITES_ENABLED:
from django.contrib.sites.models import Site

app.sites.add(Site.objects.get_current())
self.app = app

def get_draugiem_login_response(self):
Expand Down
15 changes: 11 additions & 4 deletions allauth/socialaccount/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
from django.contrib.auth.models import AnonymousUser
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.sites.models import Site
from django.test.client import RequestFactory
from django.test.utils import override_settings
from django.urls import reverse
from django.utils.http import urlencode

import allauth.app_settings

from ..account import app_settings as account_settings
from ..account.models import EmailAddress
from ..account.utils import user_email, user_username
Expand All @@ -34,7 +35,10 @@ def setup_app(provider):
key=provider.id,
secret="dummy",
)
app.sites.add(Site.objects.get_current())
if allauth.app_settings.SITES_ENABLED:
from django.contrib.sites.models import Site

app.sites.add(Site.objects.get_current())
return app


Expand Down Expand Up @@ -269,7 +273,6 @@ class Class(OAuth2TestsMixin, TestCase):
class SocialAccountTests(TestCase):
def setUp(self):
super(SocialAccountTests, self).setUp()
site = Site.objects.get_current()
for provider in providers.registry.get_list():
app = SocialApp.objects.create(
provider=provider.id,
Expand All @@ -278,7 +281,11 @@ def setUp(self):
key="123",
secret="dummy",
)
app.sites.add(site)
if allauth.app_settings.SITES_ENABLED:
from django.contrib.sites.models import Site

site = Site.objects.get_current()
app.sites.add(site)

@override_settings(
SOCIALACCOUNT_AUTO_SIGNUP=True,
Expand Down
12 changes: 9 additions & 3 deletions allauth/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from django.utils.http import base36_to_int, int_to_base36
from django.views import csrf

from allauth import app_settings

from . import utils


Expand Down Expand Up @@ -170,15 +172,19 @@ class SomeBinaryModel(models.Model):
self.assertEqual(deserialized.bb_empty, b"")

def test_build_absolute_uri(self):
request = None
if not app_settings.SITES_ENABLED:
request = self.factory.get("/")
request.META["SERVER_NAME"] = "example.com"
self.assertEqual(
utils.build_absolute_uri(None, "/foo"), "http://example.com/foo"
utils.build_absolute_uri(request, "/foo"), "http://example.com/foo"
)
self.assertEqual(
utils.build_absolute_uri(None, "/foo", protocol="ftp"),
utils.build_absolute_uri(request, "/foo", protocol="ftp"),
"ftp://example.com/foo",
)
self.assertEqual(
utils.build_absolute_uri(None, "http://foo.com/bar"),
utils.build_absolute_uri(request, "http://foo.com/bar"),
"http://foo.com/bar",
)

Expand Down
9 changes: 8 additions & 1 deletion allauth/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import django
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
from django.core.serializers.json import DjangoJSONEncoder
from django.core.validators import ValidationError, validate_email
Expand All @@ -25,6 +24,8 @@
from django.utils import dateparse
from django.utils.encoding import force_bytes, force_str

from allauth import app_settings


# Magic number 7: if you run into collisions with this number, then you are
# of big enough scale to start investing in a decent user model...
Expand Down Expand Up @@ -271,6 +272,12 @@ def build_absolute_uri(request, location, protocol=None):
from .account import app_settings as account_settings

if request is None:
if not app_settings.SITES_ENABLED:
raise ImproperlyConfigured(
"Passing `request=None` requires `sites` to be enabled."
)
from django.contrib.sites.models import Site

site = Site.objects.get_current()
bits = urlsplit(location)
if not (bits.scheme and bits.netloc):
Expand Down
1 change: 1 addition & 0 deletions test_settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
SECRET_KEY = "psst"
SITE_ID = 1
ALLOWED_HOSTS = ("*",)

DATABASES = {
"default": {
Expand Down

0 comments on commit 16ee545

Please sign in to comment.