mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 08:51:09 -05:00
first commit
This commit is contained in:
235
accounts/views.py
Normal file
235
accounts/views.py
Normal file
@@ -0,0 +1,235 @@
|
||||
from django.views.generic import DetailView, TemplateView
|
||||
from django.contrib.auth import get_user_model, login, authenticate
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib import messages
|
||||
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
|
||||
from allauth.socialaccount.providers.discord.views import DiscordOAuth2Adapter
|
||||
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.db.models import Prefetch
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from accounts.models import User, PasswordReset
|
||||
from reviews.models import Review
|
||||
from email_service.services import EmailService
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
@login_required
|
||||
def user_redirect_view(request):
|
||||
"""Redirect /user/ to the logged-in user's profile"""
|
||||
return redirect('profile', username=request.user.username)
|
||||
|
||||
def email_required(request):
|
||||
"""Handle cases where social auth provider doesn't provide an email"""
|
||||
sociallogin = request.session.get('socialaccount_sociallogin')
|
||||
if not sociallogin:
|
||||
messages.error(request, 'No social login in progress')
|
||||
return redirect('/')
|
||||
|
||||
if request.method == 'POST':
|
||||
email = request.POST.get('email')
|
||||
if email:
|
||||
sociallogin.user.email = email
|
||||
sociallogin.save()
|
||||
login(request, sociallogin.user)
|
||||
del request.session['socialaccount_sociallogin']
|
||||
messages.success(request, 'Successfully logged in')
|
||||
return redirect('/')
|
||||
else:
|
||||
messages.error(request, 'Email is required')
|
||||
return render(request, 'accounts/email_required.html', {'error': 'Email is required'})
|
||||
|
||||
return render(request, 'accounts/email_required.html')
|
||||
|
||||
class ProfileView(DetailView):
|
||||
model = User
|
||||
template_name = 'accounts/profile.html'
|
||||
context_object_name = 'profile_user'
|
||||
slug_field = 'username'
|
||||
slug_url_kwarg = 'username'
|
||||
|
||||
def get_queryset(self):
|
||||
# Optimize the base queryset with select_related
|
||||
return User.objects.select_related('profile')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
user = self.get_object()
|
||||
|
||||
# Get user's reviews with optimized queries
|
||||
reviews_queryset = Review.objects.filter(
|
||||
user=user,
|
||||
is_published=True
|
||||
).select_related(
|
||||
'user',
|
||||
'user__profile',
|
||||
'content_type'
|
||||
).prefetch_related(
|
||||
'content_object' # This will fetch the related ride/park/etc.
|
||||
).order_by('-created_at')[:5]
|
||||
|
||||
context['recent_reviews'] = reviews_queryset
|
||||
|
||||
# Get user's top lists with optimized queries
|
||||
context['top_lists'] = user.top_lists.select_related(
|
||||
'user',
|
||||
'user__profile'
|
||||
).prefetch_related(
|
||||
Prefetch('items', queryset=(
|
||||
user.top_lists.through.objects.select_related(
|
||||
'content_type'
|
||||
).prefetch_related('content_object')
|
||||
))
|
||||
).order_by('-created_at')[:5]
|
||||
|
||||
return context
|
||||
|
||||
class SettingsView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'accounts/settings.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['user'] = self.request.user
|
||||
return context
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
action = request.POST.get('action')
|
||||
|
||||
if action == 'update_profile':
|
||||
# Handle profile updates
|
||||
user = request.user
|
||||
user.first_name = request.POST.get('first_name', user.first_name)
|
||||
user.last_name = request.POST.get('last_name', user.last_name)
|
||||
|
||||
if 'avatar' in request.FILES:
|
||||
user.profile.avatar = request.FILES['avatar']
|
||||
user.profile.save()
|
||||
|
||||
user.save()
|
||||
messages.success(request, 'Profile updated successfully')
|
||||
|
||||
elif action == 'change_password':
|
||||
# Handle password change
|
||||
old_password = request.POST.get('old_password')
|
||||
new_password = request.POST.get('new_password')
|
||||
|
||||
if request.user.check_password(old_password):
|
||||
request.user.set_password(new_password)
|
||||
request.user.save()
|
||||
messages.success(request, 'Password changed successfully')
|
||||
return HttpResponseRedirect(reverse('account_login'))
|
||||
else:
|
||||
messages.error(request, 'Current password is incorrect')
|
||||
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
def request_password_reset(request):
|
||||
"""Request a password reset email"""
|
||||
if request.method == 'POST':
|
||||
email = request.POST.get('email')
|
||||
if not email:
|
||||
messages.error(request, 'Email is required')
|
||||
return redirect('account_reset_password')
|
||||
|
||||
try:
|
||||
user = User.objects.get(email=email)
|
||||
# Generate token
|
||||
token = get_random_string(64)
|
||||
# Save token with expiry
|
||||
PasswordReset.objects.update_or_create(
|
||||
user=user,
|
||||
defaults={
|
||||
'token': token,
|
||||
'expires_at': timezone.now() + timedelta(hours=24)
|
||||
}
|
||||
)
|
||||
|
||||
# Get current site
|
||||
site = get_current_site(request)
|
||||
|
||||
# Send reset email
|
||||
reset_url = reverse('password_reset_confirm', kwargs={'token': token})
|
||||
context = {
|
||||
'user': user,
|
||||
'reset_url': reset_url,
|
||||
'site_name': site.name,
|
||||
}
|
||||
email_html = render_to_string('accounts/email/password_reset.html', context)
|
||||
|
||||
# Use EmailService instead of send_mail
|
||||
EmailService.send_email(
|
||||
to=email,
|
||||
subject='Reset your password',
|
||||
text='Click the link to reset your password',
|
||||
site=site,
|
||||
html=email_html
|
||||
)
|
||||
|
||||
messages.success(request, 'Password reset email sent')
|
||||
return redirect('account_login')
|
||||
except User.DoesNotExist:
|
||||
# Still show success to prevent email enumeration
|
||||
messages.success(request, 'Password reset email sent')
|
||||
return redirect('account_login')
|
||||
|
||||
return render(request, 'accounts/password_reset.html')
|
||||
|
||||
def reset_password(request, token):
|
||||
"""Reset password using token"""
|
||||
try:
|
||||
# Get valid reset token
|
||||
reset = PasswordReset.objects.select_related('user').get(
|
||||
token=token,
|
||||
expires_at__gt=timezone.now(),
|
||||
used=False
|
||||
)
|
||||
|
||||
if request.method == 'POST':
|
||||
new_password = request.POST.get('new_password')
|
||||
if new_password:
|
||||
# Reset password
|
||||
user = reset.user
|
||||
user.set_password(new_password)
|
||||
user.save()
|
||||
|
||||
# Mark token as used
|
||||
reset.used = True
|
||||
reset.save()
|
||||
|
||||
# Get current site
|
||||
site = get_current_site(request)
|
||||
|
||||
# Send confirmation email
|
||||
context = {
|
||||
'user': user,
|
||||
'site_name': site.name,
|
||||
}
|
||||
email_html = render_to_string('accounts/email/password_reset_complete.html', context)
|
||||
|
||||
# Use EmailService instead of send_mail
|
||||
EmailService.send_email(
|
||||
to=user.email,
|
||||
subject='Password Reset Complete',
|
||||
text='Your password has been reset successfully.',
|
||||
site=site,
|
||||
html=email_html
|
||||
)
|
||||
|
||||
messages.success(request, 'Password reset successfully')
|
||||
return redirect('account_login')
|
||||
else:
|
||||
messages.error(request, 'New password is required')
|
||||
|
||||
return render(request, 'accounts/password_reset_confirm.html', {'token': token})
|
||||
except PasswordReset.DoesNotExist:
|
||||
messages.error(request, 'Invalid or expired reset token')
|
||||
return redirect('account_reset_password')
|
||||
Reference in New Issue
Block a user