wagnerdelima / drf-social-oauth2

drf-social-oauth2 makes it easy to integrate Django social authentication with major OAuth2 providers, i.e., Facebook, Twitter, Google, etc.
https://drf-social-oauth2.readthedocs.io/en/latest/
MIT License
270 stars 34 forks source link

Problem with convert-token Endpoint and Custom User Model #246

Closed evie-8 closed 3 weeks ago

evie-8 commented 1 month ago

Description

My API endpoint http://127.0.0.1:8000/auth/convert-token encounters issues when creating a user, due to my custom user model which includes additional fields. The error message received is:

Steps to Reproduce

  1. Attempt to use the convert-token endpoint to create a user.
  2. The request fails with the error related to missing name and password arguments.

Expected Behavior

The user should be created successfully, even with a custom user model that includes additional fields. The convert-token endpoint should handle these fields correctly.

Actual Behavior

The error indicates that UserManager.create_user() is missing required positional arguments name and password.

Custom User Model

Here’s a snippet of my custom User model and UserManager:

# models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import gettext_lazy as _
from .manager import UserManager
from django.utils import timezone
from rest_framework_simplejwt.tokens import RefreshToken

class User(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(max_length=100, unique=True, verbose_name=_("Email Address"))
    username = models.CharField(max_length=50, unique=True, verbose_name=_("Username"))
    name = models.CharField(max_length=255, verbose_name=_("Full Name"))
    is_superuser = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_verified = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    last_login=models.DateTimeField(auto_now=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS=["name", "username"]

    objects =  UserManager()

    def __str__(self):
        return self.username

    def tokens(self):
        refresh = RefreshToken.for_user(self)

        return {
            'refresh': str(refresh),
            'access': str(refresh.access_token)
        }

    @property
    def get_full_name(self):
        return f"{self.name.title()}"
# manager.py
from django.contrib.auth.models import BaseUserManager
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.contrib.auth.models import Group

class UserManager(BaseUserManager):

    def email_validator(self, email):

        try:
            validate_email(email)
        except ValidationError:
            raise ValueError(_("Please enter a valid email address"))

    def create_user(self, email, username, name, password, **extra_fields):

        if not email:
            raise ValueError(_("Email is required"))
        email = self.normalize_email(email)
        self.email_validator(email)

        if not name:
            raise ValueError(_("Name is required"))

        if not username:
            raise ValueError(_("Username is required"))
        user = self.model(email=email, name=name, username=username, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        others_group = Group.objects.get(name='others')
        user.groups.add(others_group)

        return user

    def create_superuser(self, email, name, username, password, **extra_fields):

        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("is_active", True)
        extra_fields.setdefault("is_verified", True)

        if extra_fields.get("is_staff") is not True:
            raise ValueError(_("Superuser must have is_staff=True."))

        if extra_fields.get("is_superuser") is not True:
            raise ValueError(_("Superuser must have is_superuser=True."))

        user = self.create_user(email, name, username, password, **extra_fields)
        user.save(using=self._db)
        admin_group = Group.objects.get(name='admin')
        user.groups.add(admin_group)

        return user

Solution Needed

I need guidance on how to ensure that user creation works correctly with my custom user model through the convert-token endpoint. Specifically: