0

I was making a web app on Django. I tried to send an email verification link to any new user who registers on my website. The thing works fine when I am hosting it on localhost but upon hosting on AWS Elastic Beanstalk the email verification shows an invalid token.

models.py

from django.contrib.auth.models import User
from django.db import models

# Create your models here.
from django.utils.safestring import mark_safe


class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone = models.CharField(blank=True, max_length=20)
    address = models.CharField(blank=True, max_length=150)
    city = models.CharField(blank=True, max_length=20)
    PINcode = models.IntegerField(blank=True, null=True)
    country = models.CharField(blank=True, max_length=50)
    image = models.ImageField(blank=True, default="Users/profile.png", upload_to='images/users/')

    def __str__(self):
        return self.user.username

    def user_name(self):
        return self.user.first_name + ' ' + self.user.last_name + ' [' + self.user.username + '] '

    def image_tag(self):
        return mark_safe('<img src="{}" height="50"/>'.format(self.image.url))
    image_tag.short_description = 'Image'

forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from django.forms import TextInput, EmailInput, Select, FileInput

from user.models import UserProfile


class SignUpForm(UserCreationForm):
    username = forms.CharField(max_length=30,label= 'User Name :')
    email = forms.EmailField(max_length=200,label= 'Email :')
    first_name = forms.CharField(max_length=100, help_text='First Name', label= 'First Name :')
    last_name = forms.CharField(max_length=100, help_text='Last Name', label= 'Last Name :')

    class Meta:
        model = User
        fields = ('username', 'email','first_name','last_name', 'password1', 'password2', )
        
    def __init__(self, *args, **kwargs):
        super(SignUpForm, self).__init__(*args, **kwargs)
        self.fields["username"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Username", "aria-label": "Username", "aria-describedby": "basic-addon1" }
        self.fields["first_name"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "First Name", "aria-label": "First Name", "aria-describedby": "basic-addon1"}
        self.fields["last_name"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Last Name", "aria-label": "Last Name", "aria-describedby": "basic-addon1"}
        self.fields["email"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Email", "aria-label": "Email", "aria-describedby": "basic-addon1"}
        self.fields["password1"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Enter Password", "aria-label": "Enter Password", "aria-describedby": "basic-addon1"}
        self.fields["password2"].widget.attrs = {"class": "form-control rounded-pill", "placeholder": "Confirm Password", "aria-label": "Confirm Password", "aria-describedby": "basic-addon1"}

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.is_active)
        )
account_activation_token = TokenGenerator()

views.py

def registerPage(request):
    User = get_user_model()
    form = SignUpForm()
    if request.method == 'POST':
        form = SignUpForm(request.POST, request.FILES)
        if form.is_valid():
            email = form.cleaned_data.get('email')
            if User.objects.filter(email=email).exists():
                messages.warning(request, "Signup error!! Invalid email or email already taken")
            else: 
                user = form.save()
                user.is_active = False
                user.save()
                current_site = get_current_site(request)
                mail_subject = 'Activate your account.'
                message = render_to_string('user/email_template.html', {
                            'user': user,
                            'domain': current_site.domain,
                            'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                            'token': account_activation_token.make_token(user),
                        })
                to_email = form.cleaned_data.get('email')
                send_mail(mail_subject, message, 'myemail@gmail.com', [to_email], fail_silently=False,)
                print(send_mail)
                print(to_email)
                print(message)
                return render(request, 'user/confirm_email.html')
            
    context = {'form': form}
    return render(request, 'user/signup_form.html', context)

def activate(request, uidb64, token):
    User = get_user_model()
    try:
        uid = force_text(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None
    if user is not None and account_activation_token.check_token(user, token):
        user.is_active = True
        user.save()
        return render(request, 'user/email_confirmed.html')
    else:
        return render(request, 'user/verification_failed.html')

email_template.html

{% autoescape off %}
Hi {{ user.first_name }},
Your username is: {{ user }}
Thank you for creating an account with us Please use link below to confirm your email Id:
"http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}"

Team {{ domain }}

settings.py


import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
.......
if 'RDS_DB_NAME' in os.environ:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': os.environ['RDS_DB_NAME'],
            'USER': os.environ['RDS_USERNAME'],
            'PASSWORD': os.environ['RDS_PASSWORD'],
            'HOST': os.environ['RDS_HOSTNAME'],
            'PORT': os.environ['RDS_PORT'],
        }
    }
else:
    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname',
        'USER': 'dbuser',
        'PASSWORD': 'dbpassword',
        'HOST': 'AWSRDSEndpoint',
        'PORT': '5432',
    }
}
   
LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Kolkata'

USE_I18N = True

USE_L10N = True

USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = 'static'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'staticfiles')
]
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'myemail@gmail.com'
EMAIL_HOST_PASSWORD = 'mypassword'


MEDIA_URL = '/uploads/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/uploads')

urls.py

from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
    ....
    path('signup/', views.registerPage, name='signup_form'),
    path('activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.activate, name='activate'),
    ....
]

The verification link generated is valid when hosted on localhost but throws "invalid token" when hosted on the elastic beanstalk.

Deepjyoti De
  • 117
  • 1
  • 11

0 Answers0