Files
octopus/myproject/accounts/views.py

227 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, authenticate, logout, get_user_model
from django.contrib import messages
from django.core.mail import send_mail
from django.conf import settings
from django.urls import reverse
from django.shortcuts import redirect
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.decorators import login_required
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from .forms import PasswordResetForm
from .models import CustomUser
import uuid
def login_view(request):
if request.method == 'POST':
email = request.POST.get('email')
password = request.POST.get('password')
# Используем email как логин
user = authenticate(request, username=email, password=password)
if user is not None:
if user.is_email_confirmed: # Проверяем, подтвержден ли email
login(request, user)
# Перенаправляем на главную страницу после успешного входа
next_page = request.GET.get('next', 'index') # Если есть параметр next, переходим туда
return redirect(next_page)
else:
messages.error(request, 'Пожалуйста, подтвердите ваш email для входа.')
else:
messages.error(request, 'Неверный email или пароль.')
return render(request, 'login.html')
def logout_view(request):
logout(request)
return redirect('index')
@login_required
def profile_view(request):
return render(request, 'profile.html', {'user': request.user})
@login_required
def change_password_view(request):
if request.method == 'POST':
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important for keeping the user logged in
messages.success(request, 'Ваш пароль был успешно изменен!')
return redirect('profile')
else:
messages.error(request, 'Пожалуйста, исправьте ошибки в форме.')
else:
form = PasswordChangeForm(request.user)
return render(request, 'change_password.html', {'form': form})
def confirm_email(request, token):
user = get_object_or_404(CustomUser, email_confirmation_token=token)
if user.is_email_confirmed:
messages.info(request, 'Email уже был подтвержден.')
else:
user.confirm_email()
user.is_active = True # Активируем пользователя
user.save()
messages.success(request, 'Email успешно подтвержден! Теперь вы можете войти.')
return redirect('accounts:login')
def password_reset_request(request):
if request.method == 'POST':
form = PasswordResetForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
try:
user = CustomUser.objects.get(email=email)
# Генерируем токен восстановления
user.password_reset_token = uuid.uuid4()
user.save()
# Отправляем письмо с инструкциями по восстановлению
reset_url = request.build_absolute_uri(
reverse('accounts:password_reset_confirm', kwargs={'token': user.password_reset_token})
)
subject = 'Восстановление пароля'
message = f'Привет {user.name}!\n\nДля восстановления пароля перейдите по следующей ссылке: {reset_url}\n\nЕсли вы не запрашивали восстановление пароля, проигнорируйте это письмо.'
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [user.email]
# Выводим письмо в консоль
print(f"Письмо для восстановления пароля:\nТема: {subject}\nСообщение:\n{message}\nПолучатель: {recipient_list}")
messages.success(request, f'Инструкции по восстановлению пароля отправлены на {email}')
except CustomUser.DoesNotExist:
# Для безопасности не сообщаем, что пользователя не существует
messages.success(request, 'Если аккаунт с таким email существует, инструкции по восстановлению пароля были отправлены на него.')
return redirect('accounts:login')
else:
form = PasswordResetForm()
return render(request, 'login.html', {'form': form})
def password_reset_confirm(request, token):
try:
user = CustomUser.objects.get(password_reset_token=token)
except CustomUser.DoesNotExist:
messages.error(request, 'Ссылка для восстановления пароля недействительна.')
return redirect('index')
if request.method == 'POST':
password1 = request.POST.get('password1')
password2 = request.POST.get('password2')
if password1 and password2 and password1 == password2:
user.set_password(password1)
user.password_reset_token = None # Обнуляем токен
user.save()
messages.success(request, 'Пароль успешно изменен. Теперь вы можете войти.')
return redirect('accounts:login')
else:
messages.error(request, 'Пароли не совпадают.')
# Отображаем форму смены пароля
return render(request, 'accounts/password_reset_confirm.html', {'user': user})
def password_setup_confirm(request, token):
"""
Позволить владельцу тенанта установить начальный пароль после одобрения регистрации.
Похоже на сброс пароля, но для новых аккаунтов.
"""
from tenants.models import TenantRegistration
from datetime import timedelta
from django.utils import timezone
# Найти регистрацию по токену
try:
registration = TenantRegistration.objects.get(
password_setup_token=token,
status=TenantRegistration.STATUS_APPROVED
)
except TenantRegistration.DoesNotExist:
messages.error(request, 'Ссылка для настройки пароля недействительна.')
return redirect('index')
# Проверить истечение токена (7 дней)
if registration.password_setup_token_created_at:
expires_at = registration.password_setup_token_created_at + timedelta(days=7)
if timezone.now() > expires_at:
messages.error(
request,
'Ссылка для настройки пароля истекла. Пожалуйста, свяжитесь с поддержкой.'
)
return redirect('index')
# Получить тенант и пользователя-владельца
from django.db import connection
tenant = registration.tenant
if not tenant:
messages.error(request, 'Тенант не найден.')
return redirect('index')
# Переключиться на схему тенанта чтобы найти владельца
connection.set_tenant(tenant)
User = get_user_model()
try:
owner = User.objects.get(email=registration.owner_email)
except User.DoesNotExist:
connection.set_schema_to_public()
messages.error(request, 'Пользователь не найден.')
return redirect('index')
# Обработать POST - установить пароль
if request.method == 'POST':
password1 = request.POST.get('password1')
password2 = request.POST.get('password2')
if password1 and password2 and password1 == password2:
# Установить пароль и активировать аккаунт
owner.set_password(password1)
owner.is_active = True
owner.save()
# Очистить токен
connection.set_schema_to_public()
registration.password_setup_token = None
registration.password_setup_token_created_at = None
registration.save()
# Автоматический вход
connection.set_tenant(tenant)
login(request, owner, backend='django.contrib.auth.backends.ModelBackend')
messages.success(
request,
f'Пароль успешно установлен! Добро пожаловать в {tenant.name}!'
)
# Перенаправить на домен тенанта
tenant_url = f'http://{tenant.schema_name}.localhost:8000/'
return redirect(tenant_url)
else:
messages.error(request, 'Пароли не совпадают.')
connection.set_schema_to_public()
# Отрисовать форму установки пароля
return render(request, 'accounts/password_setup_confirm.html', {
'registration': registration,
'tenant': tenant
})