Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Help Needed] TypeError: UserType fields cannot be resolved on a custom user model #532

Open
ash-lyrid opened this issue Apr 27, 2024 · 8 comments

Comments

@ash-lyrid
Copy link

ash-lyrid commented Apr 27, 2024

I am trying to use this package, coming from django graphene auth background.

I am getting the following error - TypeError: UserType fields cannot be resolved. GraphQL type for model field 'users.User.email' has not been implemented

GqlAuthSettings

    LOGIN_REQUIRE_CAPTCHA=False,
    REGISTER_REQUIRE_CAPTCHA=False,
    ALLOW_LOGIN_NOT_VERIFIED=True,
    LOGIN_FIELDS={email_field, password_field},
    REGISTER_MUTATION_FIELDS={email_field},

CustomUserModel

class User(AbstractBaseUser, PermissionsMixin):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = LowercaseEmailField(
        verbose_name=_("email address"), unique=True,
        error_messages={
            'unique': _(
                "A user is already registered with this email address"),
        },
    )
    first_name = models.CharField(_('first name'), max_length=150)
    middle_name = models.CharField(_('middle name'), max_length=150, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    is_staff = models.BooleanField(
        verbose_name=_("staff status"),
        default=False,
        help_text=_(
            "Designates whether the user can log into this admin site."
        ),
    )
    is_active = models.BooleanField(
        verbose_name=_("active"),
        default=True,
        help_text=_(
            "Designates whether this user should be treated as active. "
            "Unselect this instead of deleting accounts."
        ),
    )
    date_joined = models.DateTimeField(verbose_name=_("date joined"), default=timezone.now)
    mobile_number = PhoneNumberField(blank=True)
    modified = models.DateTimeField(auto_now=True)

schema.py

from typing import AsyncGenerator

import strawberry
import strawberry_django
from strawberry.types import Info
from strawberry_django.permissions import IsAuthenticated

from gqlauth.user import arg_mutations
from gqlauth.core.utils import get_user
from gqlauth.user.resolvers import Captcha
from gqlauth.user.queries import UserQueries
from gqlauth.core.middlewares import JwtSchema


@strawberry.type
class Query(UserQueries):
    @strawberry_django.field(
        directives=[
            IsAuthenticated(),
        ]
    )
    def whatsMyUserName(self, info: Info) -> str:
        return get_user(info).username

    @strawberry.field()
    def amIAnonymous(self, info: Info) -> bool:
        user = get_user(info)
        return not user.is_authenticated


@strawberry.type
class Mutation:

    verify_token = arg_mutations.VerifyToken.field
    update_account = arg_mutations.UpdateAccount.field
    archive_account = arg_mutations.ArchiveAccount.field
    delete_account = arg_mutations.DeleteAccount.field
    password_change = arg_mutations.PasswordChange.field

    captcha = Captcha.field
    token_auth = arg_mutations.ObtainJSONWebToken.field
    register = arg_mutations.Register.field
    verify_account = arg_mutations.VerifyAccount.field
    resend_activation_email = arg_mutations.ResendActivationEmail.field
    send_password_reset_email = arg_mutations.SendPasswordResetEmail.field
    password_reset = arg_mutations.PasswordReset.field
    password_set = arg_mutations.PasswordSet.field
    refresh_token = arg_mutations.RefreshToken.field
    revoke_token = arg_mutations.RevokeToken.field


@strawberry.type
class Subscription:
    @strawberry.subscription()
    async def whatsMyName(self, info: Info, target: int = 10) -> AsyncGenerator[str, None]:
        user = get_user(info)
        assert user.is_authenticated
        for _ in range(target):
            yield get_user(info).username


schema = JwtSchema(query=Query, mutation=Mutation, subscription=Subscription)
@ash-lyrid
Copy link
Author

ash-lyrid commented Apr 28, 2024

I think there is no straight forward way to add the email type to the user type as I am using a custom email field. I can see there is a TODO item to support custom UserType implementation. I will wait till that is implemented as I am unable to use this package for the time being. Please correct me if there is an alternative way to resolve this. Thanks.

@nrbnlulu
Copy link
Owner

what's your email_field?

@ash-lyrid
Copy link
Author

ash-lyrid commented May 12, 2024

from gqlauth.settings_type import GqlAuthSettings, password_field, email_field
I am using email_field from gqlauth only

This is my custom email field.

class LowercaseEmailField(models.EmailField):
    """
    Override EmailField to convert emails to lowercase before saving.
    """
    def to_python(self, value):
        """
        Convert email to lowercase.
        """
        value = super(LowercaseEmailField, self).to_python(value)
        # Value can be None so check that it's a string before lowercasing.
        if isinstance(value, str):
            return value.lower()
        return value

@nrbnlulu
Copy link
Owner

nrbnlulu commented May 12, 2024

Can you show your GQLAUTH_SETTINGS? including the implementations of email_field etc
and a full stacktrace

@ash-lyrid
Copy link
Author

GQL_AUTH = GqlAuthSettings(
    LOGIN_REQUIRE_CAPTCHA=False,
    REGISTER_REQUIRE_CAPTCHA=False,
    ALLOW_LOGIN_NOT_VERIFIED=True,
    LOGIN_FIELDS={email_field, password_field},
    REGISTER_MUTATION_FIELDS={email_field},
    # CAPTCHA_EXPIRATION_DELTA=timedelta(seconds=120),
    # CAPTCHA_MAX_RETRIES=5,
    # CAPTCHA_TEXT_FACTORY=default_text_factory,
    # CAPTCHA_TEXT_VALIDATOR=default_captcha_text_validator,
    # FORCE_SHOW_CAPTCHA=False,
    # CAPTCHA_SAVE_IMAGE=False,
    UPDATE_MUTATION_FIELDS={email_field},
    JWT_PAYLOAD_PK=email_field,
)

Traceback (most recent call last):
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/graphql/type/definition.py", line 808, in fields
    fields = resolve_thunk(self._fields)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/graphql/type/definition.py", line 300, in resolve_thunk
    return thunk() if callable(thunk) else thunk
           ^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry/schema/schema_converter.py", line 525, in <lambda>
    fields=lambda: self.get_graphql_fields(object_type),
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry/schema/schema_converter.py", line 382, in get_graphql_fields
    return _get_thunk_mapping(
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry/schema/schema_converter.py", line 129, in _get_thunk_mapping
    field_type = field.type
                 ^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry/field.py", line 302, in type
    return self.resolve_type()
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry_django/fields/base.py", line 184, in resolve_type
    resolved_type = resolve_model_field_type(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry_django/fields/types.py", line 508, in resolve_model_field_type
    raise NotImplementedError(
NotImplementedError: GraphQL type for model field 'users.User.email' has not been implemented

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/ashish/Projects/Lyrid/FreeI/manage.py", line 24, in <module>
    main()
  File "/Users/ashish/Projects/Lyrid/FreeI/manage.py", line 19, in main
    execute_from_command_line(sys.argv)
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/management/base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 88, in execute
    return super().execute(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/management/base.py", line 453, in execute
    self.check()
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/management/base.py", line 485, in check
    all_issues = checks.run_checks(
                 ^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/checks/registry.py", line 88, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/checks/urls.py", line 14, in check_url_config
    return check_resolver(resolver)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/core/checks/urls.py", line 24, in check_resolver
    return check_method()
           ^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/urls/resolvers.py", line 494, in check
    for pattern in self.url_patterns:
                   ^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/utils/functional.py", line 57, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
                                         ^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/urls/resolvers.py", line 715, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
                       ^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/utils/functional.py", line 57, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
                                         ^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/django/urls/resolvers.py", line 708, in urlconf_module
    return import_module(self.urlconf_name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/[email protected]/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/Users/ashish/Projects/Lyrid/FreeI/config/urls.py", line 6, in <module>
    from .schema import schema
  File "/Users/ashish/Projects/Lyrid/FreeI/config/schema.py", line 64, in <module>
    schema = JwtSchema(
             ^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/strawberry/schema/schema.py", line 143, in __init__
    self._schema = GraphQLSchema(
                   ^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/graphql/type/schema.py", line 224, in __init__
    collect_referenced_types(query)
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/graphql/type/schema.py", line 433, in collect_referenced_types
    collect_referenced_types(field.type)
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/graphql/type/schema.py", line 432, in collect_referenced_types
    for field in named_type.fields.values():
                 ^^^^^^^^^^^^^^^^^
  File "/usr/local/Cellar/[email protected]/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/functools.py", line 1001, in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
  File "/Users/ashish/Env/FreeI/lib/python3.11/site-packages/graphql/type/definition.py", line 811, in fields
    raise cls(f"{self.name} fields cannot be resolved. {error}") from error
TypeError: UserType fields cannot be resolved. GraphQL type for model field 'users.User.email' has not been implemented

@nrbnlulu
Copy link
Owner

Dude where do you get email_field from ?

@ash-lyrid
Copy link
Author

Using the following.
from gqlauth.settings_type import GqlAuthSettings, password_field, email_field

@nrbnlulu
Copy link
Owner

I see, thats weird. could you create a reproducible example?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants