From e8ade314a68c27634ba4ee4555ea40c2d31679fe Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 16 Aug 2025 12:35:26 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Remove=20email=20verification=20?= =?UTF-8?q?system=20and=20update=20event=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove email_verified field from User model - Delete EmailVerificationToken model and related views - Update registration to auto-login users without verification - Change event URL from /event-invitation/ to /event/ - Update Railway deployment configuration - Remove email verification templates and URLs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- ...005_remove_user_email_verified_and_more.py | 20 ++ authentication/models.py | 25 --- authentication/urls.py | 2 - authentication/views.py | 120 +---------- core/views.py | 2 +- railway.json | 2 +- .../authentication/resend_verification.html | 190 ------------------ 7 files changed, 27 insertions(+), 334 deletions(-) create mode 100644 authentication/migrations/0005_remove_user_email_verified_and_more.py delete mode 100644 templates/authentication/resend_verification.html diff --git a/authentication/migrations/0005_remove_user_email_verified_and_more.py b/authentication/migrations/0005_remove_user_email_verified_and_more.py new file mode 100644 index 0000000..5549297 --- /dev/null +++ b/authentication/migrations/0005_remove_user_email_verified_and_more.py @@ -0,0 +1,20 @@ +# Generated by Django 5.2.4 on 2025-08-16 06:59 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentication", "0004_user_email_verified_emailverificationtoken"), + ] + + operations = [ + migrations.RemoveField( + model_name="user", + name="email_verified", + ), + migrations.DeleteModel( + name="EmailVerificationToken", + ), + ] diff --git a/authentication/models.py b/authentication/models.py index c41df9d..f98b2ed 100644 --- a/authentication/models.py +++ b/authentication/models.py @@ -11,7 +11,6 @@ class User(AbstractUser): wallet_balance = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00'), db_index=True) created_at = models.DateTimeField(auto_now_add=True, db_index=True) updated_at = models.DateTimeField(auto_now=True) - email_verified = models.BooleanField(default=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] @@ -120,27 +119,3 @@ class PasswordResetToken(models.Model): return f"Password reset token for {self.user.email}" -class EmailVerificationToken(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='email_verification_tokens') - token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) - created_at = models.DateTimeField(auto_now_add=True) - expires_at = models.DateTimeField() - is_used = models.BooleanField(default=False) - - def save(self, *args, **kwargs): - if not self.expires_at: - self.expires_at = timezone.now() + timedelta(hours=24) # 24-hour expiration for email verification - super().save(*args, **kwargs) - - def is_valid(self): - return not self.is_used and timezone.now() < self.expires_at - - def mark_as_used(self): - self.is_used = True - self.save() - - class Meta: - ordering = ['-created_at'] - - def __str__(self): - return f"Email verification token for {self.user.email}" diff --git a/authentication/urls.py b/authentication/urls.py index 0680f37..7e3832e 100644 --- a/authentication/urls.py +++ b/authentication/urls.py @@ -10,6 +10,4 @@ urlpatterns = [ path('profile/', views.profile_view, name='profile'), path('forgot-password/', views.forgot_password_view, name='forgot_password'), path('reset-password//', views.reset_password_view, name='reset_password'), - path('verify-email//', views.verify_email_view, name='verify_email'), - path('resend-verification/', views.resend_verification_view, name='resend_verification'), ] \ No newline at end of file diff --git a/authentication/views.py b/authentication/views.py index 5f6d8ac..9d4bc24 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -10,7 +10,7 @@ from django.urls import reverse from django_ratelimit.decorators import ratelimit from django_ratelimit import UNSAFE from django_ratelimit.exceptions import Ratelimited -from .models import User, PasswordResetToken, EmailVerificationToken +from .models import User, PasswordResetToken import logging logger = logging.getLogger(__name__) @@ -35,48 +35,6 @@ def validate_password_strength(password): return [] -def send_verification_email(user): - """Send email verification to new user""" - try: - # Create verification token - verification_token = EmailVerificationToken.objects.create(user=user) - - # Build verification URL - verification_path = reverse('authentication:verify_email', kwargs={'token': verification_token.token}) - verification_url = f"{settings.SITE_URL}{verification_path}" - - # Send email - subject = 'Verify Your Email Address - Quantum Tasks AI' - message = f''' -Hello {user.username}, - -Welcome to Quantum Tasks AI! Please verify your email address to complete your account setup. - -Click the link below to verify your email: -{verification_url} - -This link will expire in 24 hours. - -If you didn't create this account, please ignore this email. - -Best regards, -Quantum Tasks AI Team - ''' - - send_mail( - subject, - message, - settings.DEFAULT_FROM_EMAIL, - [user.email], - fail_silently=False, - ) - - logger.info(f"Verification email sent successfully to {user.email}") - return True - - except Exception as e: - logger.error(f"Failed to send verification email to {user.email}: {str(e)}") - return False def handle_ratelimited(request, exception): @@ -108,12 +66,6 @@ def login_view(request): user = authenticate(request, username=email, password=password) if user is not None: - # Check if email is verified (only if email verification is required) - if settings.REQUIRE_EMAIL_VERIFICATION and not user.email_verified: - messages.warning(request, 'Please verify your email address before logging in. Check your inbox for the verification link.') - # Store resend URL in context for template - context = {'show_resend_verification': True} - return render(request, 'authentication/login.html', context) login(request, user) # Clear rate limit flag on successful login @@ -168,24 +120,10 @@ def register_view(request): password=password1 ) - # Handle email verification based on settings - if settings.REQUIRE_EMAIL_VERIFICATION: - # Don't automatically login - require email verification first - # Send verification email - if send_verification_email(user): - messages.success(request, 'Account created. Check your email to verify.') - else: - messages.warning(request, 'Account created. Email verification failed - try again later.') - - return redirect('authentication:login') - else: - # Skip email verification - auto-verify and login - user.email_verified = True - user.save() - - login(request, user) - messages.success(request, f'Welcome {user.username}!') - return redirect('core:homepage') + # Auto-login new users (no email verification required) + login(request, user) + messages.success(request, f'Welcome {user.username}!') + return redirect('core:homepage') except Exception as e: logger.error(f"Error creating account for {email}: {str(e)}") messages.error(request, 'Error creating account') @@ -353,53 +291,5 @@ def reset_password_view(request, token): return render(request, 'authentication/reset_password.html', {'token': token}) -def verify_email_view(request, token): - """Email verification view""" - verification_token = get_object_or_404(EmailVerificationToken, token=token) - - if not verification_token.is_valid(): - messages.error(request, 'This verification link has expired or is invalid.') - return redirect('authentication:login') - - # Mark email as verified - user = verification_token.user - user.email_verified = True - user.save() - - # Mark token as used - verification_token.mark_as_used() - - messages.success(request, 'Email verified. You can now log in.') - return redirect('authentication:login') -@ratelimit(key='ip', rate='2/5m', method=UNSAFE, block=False) -def resend_verification_view(request): - """Resend email verification""" - # Check if rate limited - if getattr(request, 'limited', False): - logger.warning(f"Verification resend rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}") - messages.error(request, 'Too many verification requests. Please try again in a few minutes.') - return redirect('authentication:login') - - if request.method == 'POST': - email = request.POST.get('email') - - try: - user = User.objects.get(email=email) - - if user.email_verified: - messages.info(request, 'Your email is already verified. You can log in.') - return redirect('authentication:login') - - # Send new verification email - if send_verification_email(user): - messages.success(request, 'Verification email sent.') - else: - messages.error(request, 'Unable to send verification email at this time.') - - except User.DoesNotExist: - # Show same success message to prevent user enumeration - messages.success(request, 'If an account with that email exists, a verification email has been sent.') - - return render(request, 'authentication/resend_verification.html') diff --git a/core/views.py b/core/views.py index 0423cc2..95552f7 100644 --- a/core/views.py +++ b/core/views.py @@ -286,7 +286,7 @@ def health_check_view(request): # Simple external service wrapper configurations EXTERNAL_PAGES = { - 'event-invitation': { + 'event': { 'title': 'Event Registration', 'description': 'Register for our upcoming event', 'external_url': 'https://form.jotform.com/252214924850455', diff --git a/railway.json b/railway.json index d686186..d1a10c2 100644 --- a/railway.json +++ b/railway.json @@ -4,7 +4,7 @@ "builder": "NIXPACKS" }, "deploy": { - "startCommand": "python manage.py migrate; python manage.py reset_admin; python manage.py verify_email admin@quantumtaskai.com --force || true; python manage.py collectstatic --noinput && gunicorn netcop_hub.wsgi:application --bind 0.0.0.0:$PORT --workers 1 --timeout 60", + "startCommand": "python manage.py migrate; python manage.py reset_admin; python manage.py collectstatic --noinput && gunicorn netcop_hub.wsgi:application --bind 0.0.0.0:$PORT --workers 1 --timeout 60", "restartPolicyType": "ON_FAILURE", "restartPolicyMaxRetries": 3 }, diff --git a/templates/authentication/resend_verification.html b/templates/authentication/resend_verification.html deleted file mode 100644 index 1b4891f..0000000 --- a/templates/authentication/resend_verification.html +++ /dev/null @@ -1,190 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Resend Email Verification{% endblock %} - -{% block extra_css %} - - -{% endblock %} - -{% block content %} - -{% endblock %} - -{% block extra_js %} - -{% endblock %} \ No newline at end of file