CC Upgrade 20250602

Fix custom allauth integration
This commit is contained in:
Alejandro Franco 2025-06-02 22:29:49 -06:00
parent c02d5461bb
commit 3d3d06fb8b
13 changed files with 27 additions and 31 deletions

View File

@ -337,7 +337,7 @@ CELERY_WORKER_HIJACK_ROOT_LOGGER = False
# ------------------------------------------------------------------------------
ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True)
# https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_AUTHENTICATION_METHOD = "{{cookiecutter.username_type}}"
ACCOUNT_LOGIN_METHODS = {"{{cookiecutter.username_type}}"}
# https://docs.allauth.org/en/latest/account/configuration.html
{%- if cookiecutter.username_type == "username" %}
ACCOUNT_SIGNUP_FIELDS = ["email*", "username*", "password1*", "password2*"]

View File

@ -44,7 +44,8 @@ EMAIL_PORT = 1025
{%- else -%}
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = env(
"DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend",
"DJANGO_EMAIL_BACKEND",
default="django.core.mail.backends.console.EmailBackend",
)
{%- endif %}

View File

@ -9,7 +9,6 @@ volumes:
production_redis_data: {}
{% endif %}
services:
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
build:
@ -75,9 +74,7 @@ services:
- production_redis_data:/data
{% endif %}
{%- if cookiecutter.use_celery == 'y' %}
celeryworker:
<<: *django
image: {{ cookiecutter.project_slug }}_production_celeryworker

View File

@ -1,7 +1,7 @@
export COMPOSE_FILE := "docker-compose.local.yml"
## Just does not yet manage signals for subprocesses reliably, which can lead to unexpected behavior.
## Exercise caution before expanding its usage in production environments.
## Exercise caution before expanding its usage in production environments.
## For more information, see https://github.com/casey/just/issues/2473 .

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
from pathlib import Path

View File

@ -8,13 +8,12 @@ from allauth.core.exceptions import ImmediateHttpResponse
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from django.conf import settings
from django.contrib import messages
from django.http import HttpRequest
from django.shortcuts import redirect
from django.urls import reverse
if typing.TYPE_CHECKING:
from allauth.socialaccount.models import SocialLogin
from {{cookiecutter.project_slug}}.users.models import User
from django.http import HttpRequest
class AccountAdapter(DefaultAccountAdapter):
@ -30,8 +29,6 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter):
) -> bool:
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
def pre_social_login(self, request, sociallogin):
# social account already exists, so this is just a login
if sociallogin.is_existing:
@ -53,13 +50,13 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter):
return
if request.user.is_authenticated and request.user.email != verified_email.email:
# Obtener el nombre del proveedor social de manera más segura
provider_name = sociallogin.account.provider.capitalize()
messages.error(
request,
(
"No es posible enlazar tu cuenta de {}, "
f"No es posible enlazar tu cuenta de {provider_name}, "
"ya que no coincide con tu correo en esta plataforma."
).format(
list(request._socialapp_cache.keys())[0].capitalize()
),
)
raise ImmediateHttpResponse(redirect(reverse("socialaccount_connections")))
@ -68,7 +65,8 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter):
# an existing user's account
try:
existing_email = EmailAddress.objects.get(
email__iexact=verified_email.email, verified=True
email__iexact=verified_email.email,
verified=True
)
except EmailAddress.DoesNotExist:
return

View File

@ -12,5 +12,5 @@ class UserSerializer(serializers.ModelSerializer[User]):
fields = ["username", "email", "uuid", "first_name", "last_name", "url"]
{%- endif %}
extra_kwargs = {
"url": {"view_name": "api:user-detail", "lookup_field": "uuid"}
"url": {"view_name": "api:user-detail", "lookup_field": "uuid"},
}

View File

@ -1,4 +1,5 @@
import uuid
from django.contrib.auth import get_user_model
from rest_framework import status
from rest_framework.decorators import action

View File

@ -1,9 +1,8 @@
from allauth.account.forms import SignupForm
from allauth.socialaccount.forms import SignupForm as SocialSignupForm
from django import forms
from django.contrib.auth import forms as admin_forms
{%- if cookiecutter.username_type == "email" %}
from django.forms import EmailField
{%- endif %}
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
User = get_user_model()
@ -13,7 +12,7 @@ class UserAdminChangeForm(admin_forms.UserChangeForm):
class Meta(admin_forms.UserChangeForm.Meta): # type: ignore[name-defined]
model = User
{%- if cookiecutter.username_type == "email" %}
field_classes = {"email": EmailField}
field_classes = {"email": forms.EmailField}
{%- endif %}
@ -27,7 +26,7 @@ class UserAdminCreationForm(admin_forms.AdminUserCreationForm):
model = User
{%- if cookiecutter.username_type == "email" %}
fields = ("email", "first_name", "last_name")
field_classes = {"email": EmailField}
field_classes = {"email": forms.EmailField}
error_messages = {
"email": {"unique": _("This email has already been taken.")},
}

View File

@ -4,10 +4,7 @@ from typing import ClassVar
{% endif -%}
from django.contrib.auth.models import AbstractUser
from django.db.models import CharField
{%- if cookiecutter.username_type == "email" %}
from django.db.models import EmailField
{%- endif %}
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
{%- if cookiecutter.username_type == "email" %}
@ -24,12 +21,15 @@ class User(AbstractUser):
"""
uuid = models.UUIDField(
unique=True, db_index=True, default=uuid_lib.uuid4, editable=False
unique=True,
db_index=True,
default=uuid_lib.uuid4,
editable=False
)
first_name = models.CharField(_("first name"), max_length=150)
last_name = models.CharField(_("last name"), max_length=150)
{%- if cookiecutter.username_type == "email" %}
email = EmailField(_("email address"), unique=True)
email = models.EmailField(_("email address"), unique=True)
username = None # type: ignore[assignment]
USERNAME_FIELD = "email"

View File

@ -6,6 +6,8 @@ from factory import Faker
from factory import post_generation
from factory.django import DjangoModelFactory
from {{ cookiecutter.project_slug }}.users.models import User
class UserFactory(DjangoModelFactory[User]):
{%- if cookiecutter.username_type == "username" %}

View File

@ -5,10 +5,7 @@ from {{ cookiecutter.project_slug }}.users.models import User
def test_detail(user: User):
assert (
reverse("users:detail", kwargs={"uuid": user.uuid})
== f"/users/{user.uuid}/"
)
assert reverse("users:detail", kwargs={"uuid": user.uuid}) == f"/users/{user.uuid}/"
assert resolve(f"/users/{user.uuid}/").view_name == "users:detail"

View File

@ -28,7 +28,7 @@ class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
assert self.request.user.is_authenticated # type guard
return self.request.user.get_absolute_url()
def get_object(self, queryset: QuerySet | None=None) -> User:
def get_object(self, queryset: QuerySet | None = None) -> User:
assert self.request.user.is_authenticated # type guard
return self.request.user