first commit

This commit is contained in:
pacnpal
2024-10-28 17:09:57 -04:00
commit 2e1b4d7af7
9993 changed files with 1182741 additions and 0 deletions

235
accounts/views.py Normal file
View 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')