বাংলায় জ্যাঙ্গো

জ্যাঙ্গোতে ইমেল ভেরিফিকশেনর মাধ্যমে কিভাবে ইউজার রেজিষ্ট্রেশন সম্পন্ন করা যায়, এই টিউটোরিয়ালটিতে আমরা সে বিষয়টি শেখার চেষ্টা করবো।

Step-01:

প্রথমেই ধরে নিই যে, mysite নামে আমাদের একটি প্রজেক্ট রয়েছে যেখানে account নামে একটি অ্যাপস আছে।

ভেরিফিকেশন ইমেল পাঠানোর কাজটি করার জন্য প্রথমেই settings.py ফাইলে যেয়ে ইমেল হোস্ট সার্ভারটি সেট করে দিতে হবে। আমরা মেইল পাঠানোর কাজটি gmail smtp(simple mail transfer protocol) সার্ভার ব্যবহার করে সম্পন্ন করবো। (ইমেল পাঠানোর কাজটা আমরা sendgrid ব্যাহার করেও করতে পারি, বিস্তারিত)

mysite/settings.py:

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your_email_password'

জিমেইলের smtp সার্ভার ব্যবহার করে মেইল পাঠানোতে কোন সমস্যা হলে এটা (click here) দেখতে পারেন।

Step-02:

যখন  ইউজার জ্যাঙ্গোতে নির্ধারিত ফরমে রেজিষ্ট্রশন করবে, তখন প্রত্যেকের  জন্য আমরা একটা টোকেন (বিশেষায়িত সংখ্যা বা শব্দ) তৈরি করবো , যার উপর ভিত্তি করেই মূলত ইমেল কনফারমেশন বা ভেরিফেকশনের কাজটা সম্পন্ন করা হবে।

এর জন্য জন্য আমরা account ডিরেক্টরিতে token.py নামে নতুন একটি ফাইল তৈরি করবো।

account/token.py:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six
class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.id) + six.text_type(timestamp) +
            six.text_type(user.is_active)
        )
account_activation_token = TokenGenerator()
  • প্রথমেই PasswordResetTokenGenerator  ক্লাসটি ইমপোর্ট করা হয়েছে কাস্টম টোকেন জেনারেটর ক্লাস তৈরি করার জন্য।
  • পরবর্তীতে TokenGenerator ক্লাস তৈরি করে তার মধ্যে _make_hash_value নামের মেথডের মাধ্যমে প্রত্যেক user আইডি নিয়ে ভিন্ন ভিন্ন হ্যাশিং ভ্যালু তৈরি করার ব্যবস্থা করা হয়েছে যা মূলত টোকেন হিসেবে কাজ করবে।
  • account_activation_token নামে TokenGenerator ক্লাসের ইন্সট্যান্স তৈরি করা হয়েছে।

Step-03:

এখন আমাদেরকে user registration এর form তৈরি করতে হবে। এর জন্য সবচেয়ে ভালো উপায় হচ্ছে UserCreationForm ক্লাসটিকে ব্যবহার করা।

account ডিরেক্টরীতে forms.py নামের একটি ফাইল তৈরি করে নিতে হবে।

account/forms.py:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class UserRegistrationForm(UserCreationForm):
    email = forms.EmailField(max_length=200, help_text='Required')
    password1 = forms.CharField(label="Password",widget=forms.PasswordInput)
    password2 = forms.CharField(label="Confirm Password",widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('username','first_name','last_name','email')

    def clean_password2(self):
        cd = self.cleaned_data
        if cd['password1'] != cd['password2']:
            raise forms.ValidationError("Password didn't match")
        else:
            return cd['password2']

  •  ইউজারের ইমেল  সংগ্রহ করে কনফারমেশন মেইল প্রেরণ করার জন্য এখানে অতিরিক্ত ফিল্ড হিসেবে প্রথমেই email ব্যবহার করা হয়ছে ।
  • ইউজারের দুটি পাসওয়ার্ড (password, confirmation password) মিল আছে কিনা এটা চেক করার জন্য (clean_password2 মেথড) অতিরিক্ত password1, password2 ফিল্ড লিখা  হয়েছে।

Step-04:

account/views.py:

from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import UserRegistrationForm
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from .tokens import account_activation_token
from django.contrib.auth.models import User
from django.core.mail import EmailMessage

def signup(request):
    if request.method == 'POST':
        form = UserRegistrationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False
            user.save()
            current_site = get_current_site(request)
            mail_subject = 'Activate your blog account.'
            message = render_to_string('acc_active_email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid':urlsafe_base64_encode(force_bytes(user.id)).decode(),
                'token':account_activation_token.make_token(user),
            })
            to_email = form.cleaned_data.get('email')
            email = EmailMessage(
                        mail_subject, message, to=[to_email]
            )
            email.send()
            return HttpResponse('Please confirm your email address to complete the registration')
    else:
        form = UserRegistrationForm()
    return render(request, 'signup.html', {'form': form})

  • ইমেলে ভেরিফিকেশনের জন্য user.is_active = False করে দেয়া হয়েছে। অর্থাৎ ভেরিফিকেশনের আগে ইউজারকে প্রথমে deactive করে রাখা হয়েছে।
  • current_site ভ্যারিয়েবলের মধ্যমে get_current_site() মেথড ব্যবহার করে বর্তমান সাইটের নামটা সংগ্রহ করা হয়েছে।
  • mail_subject ভ্যারিয়েবলে মেইলের সাবজেক্ট সংক্রান্ত স্ট্রিং অবজেক্ট রাখা হয়েছে।
  • render_to_string() মেথডের মাধ্যমে কি কি context ডাটা ইমেইলে মেসেজ আকারে যাবে তা একটি টেমপ্লেট acc_active_email.html এর মাধ্যমে পাঠানো হয়েছে এবং সেটা message নামক ভ্যারিয়বলে রাখা হয়েছে। context ডাটা হিসেবে user object, domain name, user আইডি থেকে তৈরিকৃত uid এবং নির্দিষ্ট user object ব্যবহার করে (Step-02 , token.py ফাইলের মাধ্যমে) ঐ user এর জন্য token তৈরি করে পাঠানো হয়েছে। এই context ডাটাগুলো পরবর্তীতে URL এর মাধ্যমে views.py ফাইলের activate মেথেড পাঠানো হবে।
  • to_email ভ্যারিয়েবলের মধ্যে ফরম থেকে প্রাপ্ত ইউজার ইমেল সংগ্রহ করে রাখা হয়েছে।
  • তারপর  EmailMessage() মেথড ব্যবহার করে  প্রাপ্ত ইমেলে send করার ব্যবস্থা করা হয়েছে।

 

Step-05:

এখন templates ডিরেক্টরীতে acc_active_email.html নামের নতুন ফাইল তৈরি করে context থেকে প্রাপ্ত ডাটাগুলো নিয়ে ইমেইলের বডিতে মেসেজ আকারে একটা URL তৈরি করতে হবে, ডাটাগুলো views.py ফাইলের activate মেথডে পাঠানোর জন্য।

templates/acc_active_email.html:

{% autoescape off %}
Hi {{ user.username }},
Please click on the link to confirm your registration,

http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}

এখানে autoescape off করে রাখা হয়েছে, যাতে করে কনটেক্স থেকে প্রাপ্ত ডাটারগুলোর মধ্যে HTML সিনট্যাক্স থাকলে তা autoescape না করা হয়। autoescape সম্পর্কে বিস্তারি এখানে

Step-06:

এখন কাজ হবে ইমেলের মেসেজ বডি থেকে প্রাপ্ত URL থেকে token এবং uid (as uidb64)  নিয়ে activate ফাংশন লিখা, যার মাধ্যমে user.is_active=False কে user.is_active=True করে ডাটাবেসে সেভ করতে হবে।

account/views.py:

def activate(request, uidb64, token):
    try:
        uid = force_text(urlsafe_base64_decode(uidb64))
        user = User.objects.get(id=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()
        login(request, user)
        # return redirect('home')
        return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
    else:
        return HttpResponse('Activation link is invalid!')
  • uid কে টেক্সটে কনভার্ট করে user এর id বের করা হয়েছে।
  • uid এর মাধ্যমে user object কে খুঁজে বের করা হয়েছে।
  • user object যদি পাওয়া যায়, তবে account_activation_token.check_token() মেথেডর মধ্যে user object এবং token পাঠিয়ে চেক করা হয়েছে যে উক্ত user এবং token এর সাথে পূর্বে তৈরিকৃত token ম্যাচ করে কিনা।
  • user এর সাথে token চেকিং সম্পন্ন হওয়ার পর user.active=True করে দিয়ে save() মেথড ব্যবহার করে ডাটাবেসে সেভ করা হয়েছে।
  • তারপর login() মেথড ব্যবহার করে user কে login করে দেওয়া হয়েছে।

বি.দ্র: যদি  settings.py ফাইলের AUTHENTICATION_BACKENDS=[] এর মধ্যে custom কোন ব্যাকেন্ড authentication ব্যবহার করা হয়, তবে উহা  login(request, user) এর মধ্যে প্যারামিটার হিসেবে দিতে হবে। যেমন- login(request,user, backend=’account.authentication.EmailAuthBackend’)।

এখানে account.authentication.EmailAuthBackend হচ্ছে custom backend authentication।

Step-07:

account/urls.py:

path('activate/<uidb64>/<token>/',views.activate, name='activate'),

Step-08:

templates/signup.html:

{% block content %}

<h2>Sign up</h2>

<form method="post">
    {% csrf_token %}
      {% for field in form %}
      

        {{ field.label_tag }}
        {{ field }}
        {% if field.help_text %}
          <small style="display: none">{{ field.help_text }}</small>
        {% endif %}
        {% for error in field.errors %}
          {{ error }}
        {% endfor %}
      {% endfor %}
    <button type="submit">Sign up</button>
  </form>

{% endblock %}

 

[If you find any inconsistency, please let me know, Thank you 🙂 ]

Leave a Reply

avatar
  Subscribe  
Notify of