# -*- coding: utf-8 -*- from __future__ import annotations from django.contrib import messages import django.db from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView from hotpocket_backend.apps.accounts.decorators import account_required from hotpocket_backend.apps.accounts.mixins import AccountRequiredMixin from hotpocket_backend.apps.ui.forms.accounts.settings import ( FederatedPasswordForm, FederatedProfileForm, PasswordForm, ProfileForm, SettingsForm, ) @account_required def settings(request: HttpRequest) -> HttpResponse: return redirect(reverse('ui.accounts.settings.profile')) class BaseSettingsView(AccountRequiredMixin, FormView): template_name = 'ui/accounts/settings.html' @property def is_federated(self) -> bool: return all(( self.request.user.is_anonymous is False, self.request.user.has_usable_password() is False, )) def get_context_data(self, **kwargs) -> dict: result = super().get_context_data(**kwargs) result.update({ 'is_federated': self.is_federated, }) return result class ProfileView(BaseSettingsView): def get_form_class(self) -> type[ProfileForm]: if self.is_federated is True: return FederatedProfileForm return ProfileForm def get_initial(self) -> dict: result = super().get_initial() result.update({ 'username': self.request.user.username, 'first_name': self.request.user.first_name, 'last_name': self.request.user.last_name, 'email': self.request.user.email, }) return result def get_context_data(self, **kwargs) -> dict: result = super().get_context_data(**kwargs) result.update({ 'title': _('Profile'), 'active_tab': 'profile', }) return result def form_valid(self, form: ProfileForm) -> HttpResponse: assert self.is_federated is False, ( 'Refuse to save profile of a federated account: ' f'account=`{self.request.user}`' ) with django.db.transaction.atomic(): self.request.user.first_name = form.cleaned_data['first_name'] self.request.user.last_name = form.cleaned_data['last_name'] self.request.user.email = form.cleaned_data['email'] self.request.user.save() messages.add_message( self.request, messages.SUCCESS, message=_('Your profile has been been updated!'), ) return super().form_valid(form) def get_success_url(self) -> str: return reverse('ui.accounts.settings.profile') class PasswordView(BaseSettingsView): def get_form_class(self) -> type[PasswordForm]: if self.is_federated is True: return FederatedPasswordForm return PasswordForm def get_form(self, form_class: type[PasswordForm] | None = None, ) -> PasswordForm: form_class = form_class or self.get_form_class() return form_class(self.request.user, **self.get_form_kwargs()) def get_context_data(self, **kwargs) -> dict: result = super().get_context_data(**kwargs) result.update({ 'title': _('Password'), 'active_tab': 'password', }) return result def form_valid(self, form: PasswordForm) -> HttpResponse: assert self.is_federated is False, ( 'Refuse to change password of a federated account: ' f'account=`{self.request.user}`' ) with django.db.transaction.atomic(): form.set_password_and_save( self.request.user, password_field_name='new_password1', ) messages.add_message( self.request, messages.SUCCESS, message=_('Your password has been changed!'), ) return super().form_valid(form) def get_success_url(self) -> str: return reverse('ui.accounts.settings.password') class SettingsView(BaseSettingsView): form_class = SettingsForm def get_context_data(self, **kwargs) -> dict: result = super().get_context_data(**kwargs) result.update({ 'title': _('Settings'), 'active_tab': 'settings', 'is_federated': False, }) return result def get_initial(self) -> dict: return self.request.user.settings def form_valid(self, form: PasswordForm) -> HttpResponse: with django.db.transaction.atomic(): self.request.user.raw_settings = form.cleaned_data self.request.user.save() messages.add_message( self.request, messages.SUCCESS, message=_('Your settings have been updated!'), ) return super().form_valid(form) def get_success_url(self) -> str: return reverse('ui.accounts.settings.settings')