I'm using Django 2.0.10 with rest-framework, rest-auth and allauth. I have a custom user model.
I've got email verification working by using the allauth view. The verification email is sent when a user registers. If I click the link in the email, I'm taken to a page with a button to click to verify the email. This all works without error. However what I can't find out is what this actually does. No field in the user's data seems to change.
The behaviour I want is for users to be able to register and login, but only to be able to add content to the site after they have verified their email.
Edit: this post gives part of the answer but doesn't say how to save the verification status as a property of the user so that you can check it in the front end when you load the user data.
settings.py
# django rest auth
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
OLD_PASSWORD_FIELD_ENABLED = True
LOGOUT_ON_PASSWORD_CHANGE = False
ACCOUNT_EMAIL_VERIFICATION = 'optional'
api/urls.py
from allauth.account.views import confirm_email
urlpatterns = [
re_path(r'^rest-auth/registration/account-confirm-email/(?P<key>[-:\w]+)/$', confirm_email,
name='account_confirm_email'),
...
]
users/models.py
import uuid
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
from django.utils.http import int_to_base36
class CustomUserManager(UserManager):
def get_by_natural_key(self, username):
case_insensitive_username_field = '{}__iexact'.format(self.model.USERNAME_FIELD)
return self.get(**{case_insensitive_username_field: username})
ID_LENGTH = 12
def pkgen():
from base64 import b32encode
from hashlib import sha1
from random import random
pk = int_to_base36(uuid.uuid4().int)[:ID_LENGTH]
return pk
class CustomUser(AbstractUser):
objects = CustomUserManager()
slug = models.CharField(max_length=ID_LENGTH, default=pkgen, editable=False)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
def __str__(self):
return self.email
When a user logs in, how can I find out if they have verified their email address? Thanks for any help!
Aha! Thanks to this post and this post, I think I have an answer.
The email address's status is saved in a separate table EmailAdress, not as part of the User model. This can be accessed in a modelviewset as follows:
api.py
from allauth.account.admin import EmailAddress
class ListViewSet(viewsets.ModelViewSet):
...
def get_queryset(self):
# can view public lists and lists the user created
if self.request.user.is_authenticated:
print('is there a verified email address?')
print(EmailAddress.objects.filter(user=self.request.user, verified=True).exists())
...
This will return True if the user has any verified email address.
However, it's much more useful to add the verification status to the user. This can be done with a signal as explained here.
views.py
from allauth.account.signals import email_confirmed
from django.dispatch import receiver
@receiver(email_confirmed)
def email_confirmed_(request, email_address, **kwargs):
user = email_address.user
user.email_verified = True
user.save()
Now in api.py you can check like this:
print(self.request.user.email_verified)
This works if you have a single email address that can't be changed or deleted. If you allow multiple email addresses I guess you'd need to make more checks and update the user's status accordingly. But I have only a single email address which is used for login, so I think that's OK.
I think it would be better practice to make 'email_verified' part of a user profile, but this is a working demo.