from django.contrib.auth.tokens import default_token_generator from django.core.mail import send_mail from django.shortcuts import render, redirect from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes, force_text from django.conf import settings from django import forms from django.utils.translation import gettext_lazy as _ from django.urls import reverse from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from urllib.parse import urlencode, urlunparse, urlparse from judge.models import Profile from judge.utils.email_render import render_email_message class EmailChangeForm(forms.Form): new_email = forms.EmailField(label=_("New Email")) def clean_new_email(self): new_email = self.cleaned_data.get("new_email") if User.objects.filter(email=new_email).exists(): raise forms.ValidationError(_("An account with this email already exists.")) return new_email @login_required def email_change_view(request): form = EmailChangeForm(request.POST or None) if request.method == "POST" and form.is_valid(): new_email = request.POST.get("new_email") user = request.user profile = request.profile # Generate a token for email verification token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) # Send the email to the user subject = _(f"{settings.SITE_NAME} - Email Change Request") email_contexts = { "message": _( "We have received a request to change your email to this email. Click the button below to change your email:" ), "title": _("Email Change"), "button_text": _("Change Email"), "url_path": reverse( "email_change_verify", kwargs={"uidb64": uid, "token": token} ), } message = render_email_message(request, email_contexts) send_mail(subject, message, settings.EMAIL_HOST_USER, [new_email]) profile.email_change_pending = new_email profile.save() return redirect("email_change_pending") return render( request, "email_change/email_change.html", { "form": form, "title": _("Change email"), }, ) def verify_email_view(request, uidb64, token): 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 default_token_generator.check_token(user, token): # Update the user's email address profile = Profile.objects.get(user=user) new_email = profile.email_change_pending if new_email: user.email = new_email profile.email_change_pending = None user.save() profile.save() return render( request, "email_change/email_change_success.html", {"title": _("Success"), "user": user}, ) return render( request, "email_change/email_change_failure.html", {"title": _("Invalid")} ) def email_change_pending_view(request): return render( request, "email_change/email_change_pending.html", { "title": _("Email change pending"), }, )