From 87378a35339b82a6d01233f57bb412a6763233ee Mon Sep 17 00:00:00 2001 From: Sonny Bakker Date: Mon, 14 Sep 2020 20:42:03 +0200 Subject: [PATCH] Split account views into seperate files --- src/newsreader/accounts/views.py | 210 ------------------ src/newsreader/accounts/views/__init__.py | 21 ++ src/newsreader/accounts/views/auth.py | 11 + src/newsreader/accounts/views/integrations.py | 75 +++++++ src/newsreader/accounts/views/password.py | 37 +++ src/newsreader/accounts/views/registration.py | 59 +++++ src/newsreader/accounts/views/settings.py | 50 +++++ 7 files changed, 253 insertions(+), 210 deletions(-) delete mode 100644 src/newsreader/accounts/views.py create mode 100644 src/newsreader/accounts/views/__init__.py create mode 100644 src/newsreader/accounts/views/auth.py create mode 100644 src/newsreader/accounts/views/integrations.py create mode 100644 src/newsreader/accounts/views/password.py create mode 100644 src/newsreader/accounts/views/registration.py create mode 100644 src/newsreader/accounts/views/settings.py diff --git a/src/newsreader/accounts/views.py b/src/newsreader/accounts/views.py deleted file mode 100644 index 4f982a9..0000000 --- a/src/newsreader/accounts/views.py +++ /dev/null @@ -1,210 +0,0 @@ -from django.contrib import messages -from django.contrib.auth import views as django_views -from django.core.cache import cache -from django.shortcuts import render -from django.urls import reverse_lazy -from django.utils.translation import gettext as _ -from django.views.generic import RedirectView, TemplateView -from django.views.generic.edit import FormView, ModelFormMixin - -from registration.backends.default import views as registration_views - -from newsreader.accounts.forms import UserSettingsForm -from newsreader.accounts.models import User -from newsreader.news.collection.exceptions import StreamException -from newsreader.news.collection.reddit import ( - get_reddit_access_token, - get_reddit_authorization_url, -) -from newsreader.news.collection.tasks import RedditTokenTask - - -class LoginView(django_views.LoginView): - template_name = "accounts/views/login.html" - success_url = reverse_lazy("index") - - -class LogoutView(django_views.LogoutView): - next_page = reverse_lazy("accounts:login") - - -# RegistrationView shows a registration form and sends the email -# RegistrationCompleteView shows after filling in the registration form -# ActivationView is send within the activation email and activates the account -# ActivationCompleteView shows the success screen when activation was succesful -# ActivationResendView can be used when activation links are expired -# RegistrationClosedView shows when registration is disabled -class RegistrationView(registration_views.RegistrationView): - disallowed_url = reverse_lazy("accounts:register-closed") - template_name = "registration/registration_form.html" - success_url = reverse_lazy("accounts:register-complete") - - -class RegistrationCompleteView(TemplateView): - template_name = "registration/registration_complete.html" - - -class RegistrationClosedView(TemplateView): - template_name = "registration/registration_closed.html" - - -# Redirects or renders failed activation template -class ActivationView(registration_views.ActivationView): - template_name = "registration/activation_failure.html" - - def get_success_url(self, user): - return ("accounts:activate-complete", (), {}) - - -class ActivationCompleteView(TemplateView): - template_name = "registration/activation_complete.html" - - -# Renders activation form resend or resend_activation_complete -class ActivationResendView(registration_views.ResendActivationView): - template_name = "registration/activation_resend_form.html" - - def render_form_submitted_template(self, form): - """ - Renders resend activation complete template with the submitted email. - - """ - email = form.cleaned_data["email"] - context = {"email": email} - - return render( - self.request, "registration/activation_resend_complete.html", context - ) - - -# PasswordResetView sends the mail -# PasswordResetDoneView shows a success message for the above -# PasswordResetConfirmView checks the link the user clicked and -# prompts for a new password -# PasswordResetCompleteView shows a success message for the above -class PasswordResetView(django_views.PasswordResetView): - template_name = "password-reset/password-reset.html" - subject_template_name = "password-reset/password-reset-subject.txt" - email_template_name = "password-reset/password-reset-email.html" - success_url = reverse_lazy("accounts:password-reset-done") - - -class PasswordResetDoneView(django_views.PasswordResetDoneView): - template_name = "password-reset/password-reset-done.html" - - -class PasswordResetConfirmView(django_views.PasswordResetConfirmView): - template_name = "password-reset/password-reset-confirm.html" - success_url = reverse_lazy("accounts:password-reset-complete") - - -class PasswordResetCompleteView(django_views.PasswordResetCompleteView): - template_name = "password-reset/password-reset-complete.html" - - -class PasswordChangeView(django_views.PasswordChangeView): - template_name = "accounts/views/password-change.html" - success_url = reverse_lazy("accounts:settings") - - -class SettingsView(ModelFormMixin, FormView): - template_name = "accounts/views/settings.html" - success_url = reverse_lazy("accounts:settings") - form_class = UserSettingsForm - model = User - - def get(self, request, *args, **kwargs): - self.object = self.get_object() - return super().get(request, *args, **kwargs) - - def get_object(self, **kwargs): - return self.request.user - - def get_context_data(self, **kwargs): - user = self.request.user - - reddit_authorization_url = None - reddit_refresh_url = None - reddit_task_active = cache.get(f"{user.email}-reddit-refresh") - - if ( - user.reddit_refresh_token - and not user.reddit_access_token - and not reddit_task_active - ): - reddit_refresh_url = reverse_lazy("accounts:reddit-refresh") - - if not user.reddit_refresh_token: - reddit_authorization_url = get_reddit_authorization_url(user) - - return { - **super().get_context_data(**kwargs), - "reddit_authorization_url": reddit_authorization_url, - "reddit_refresh_url": reddit_refresh_url, - } - - def get_form_kwargs(self): - return {**super().get_form_kwargs(), "instance": self.request.user} - - -class RedditTemplateView(TemplateView): - template_name = "accounts/views/reddit.html" - - def get(self, request, *args, **kwargs): - context = self.get_context_data(**kwargs) - - error = request.GET.get("error", None) - state = request.GET.get("state", None) - code = request.GET.get("code", None) - - if error: - return self.render_to_response({**context, "error": error}) - - if not code or not state: - return self.render_to_response(context) - - cached_state = cache.get(f"{request.user.email}-reddit-auth") - - if state != cached_state: - return self.render_to_response( - { - **context, - "error": "The saved state for Reddit authorization did not match", - } - ) - - try: - access_token, refresh_token = get_reddit_access_token(code, request.user) - - return self.render_to_response( - { - **context, - "access_token": access_token, - "refresh_token": refresh_token, - } - ) - except StreamException as e: - return self.render_to_response({**context, "error": str(e)}) - except KeyError: - return self.render_to_response( - {**context, "error": "Access and refresh token not found in response"} - ) - - -class RedditTokenRedirectView(RedirectView): - url = reverse_lazy("accounts:settings") - - def get(self, request, *args, **kwargs): - response = super().get(request, *args, **kwargs) - - user = request.user - task_active = cache.get(f"{user.email}-reddit-refresh") - - if not task_active: - RedditTokenTask.delay(user.pk) - messages.success(request, _("Access token is being retrieved")) - cache.set(f"{user.email}-reddit-refresh", 1, 300) - return response - - messages.error(request, _("Unable to retrieve token")) - return response diff --git a/src/newsreader/accounts/views/__init__.py b/src/newsreader/accounts/views/__init__.py new file mode 100644 index 0000000..ee44f5b --- /dev/null +++ b/src/newsreader/accounts/views/__init__.py @@ -0,0 +1,21 @@ +from newsreader.accounts.views.auth import LoginView, LogoutView +from newsreader.accounts.views.integrations import ( + RedditTemplateView, + RedditTokenRedirectView, +) +from newsreader.accounts.views.password import ( + PasswordChangeView, + PasswordResetCompleteView, + PasswordResetConfirmView, + PasswordResetDoneView, + PasswordResetView, +) +from newsreader.accounts.views.registration import ( + ActivationCompleteView, + ActivationResendView, + ActivationView, + RegistrationClosedView, + RegistrationCompleteView, + RegistrationView, +) +from newsreader.accounts.views.settings import SettingsView diff --git a/src/newsreader/accounts/views/auth.py b/src/newsreader/accounts/views/auth.py new file mode 100644 index 0000000..0663768 --- /dev/null +++ b/src/newsreader/accounts/views/auth.py @@ -0,0 +1,11 @@ +from django.contrib.auth import views as django_views +from django.urls import reverse_lazy + + +class LoginView(django_views.LoginView): + template_name = "accounts/views/login.html" + success_url = reverse_lazy("index") + + +class LogoutView(django_views.LogoutView): + next_page = reverse_lazy("accounts:login") diff --git a/src/newsreader/accounts/views/integrations.py b/src/newsreader/accounts/views/integrations.py new file mode 100644 index 0000000..62edc1c --- /dev/null +++ b/src/newsreader/accounts/views/integrations.py @@ -0,0 +1,75 @@ +from django.contrib import messages +from django.core.cache import cache +from django.urls import reverse_lazy +from django.utils.translation import gettext as _ +from django.views.generic import RedirectView, TemplateView + +from newsreader.news.collection.exceptions import StreamException +from newsreader.news.collection.reddit import ( + get_reddit_access_token, + get_reddit_authorization_url, +) +from newsreader.news.collection.tasks import RedditTokenTask + + +class RedditTemplateView(TemplateView): + template_name = "accounts/views/reddit.html" + + def get(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + + error = request.GET.get("error", None) + state = request.GET.get("state", None) + code = request.GET.get("code", None) + + if error: + return self.render_to_response({**context, "error": error}) + + if not code or not state: + return self.render_to_response(context) + + cached_state = cache.get(f"{request.user.email}-reddit-auth") + + if state != cached_state: + return self.render_to_response( + { + **context, + "error": "The saved state for Reddit authorization did not match", + } + ) + + try: + access_token, refresh_token = get_reddit_access_token(code, request.user) + + return self.render_to_response( + { + **context, + "access_token": access_token, + "refresh_token": refresh_token, + } + ) + except StreamException as e: + return self.render_to_response({**context, "error": str(e)}) + except KeyError: + return self.render_to_response( + {**context, "error": "Access and refresh token not found in response"} + ) + + +class RedditTokenRedirectView(RedirectView): + url = reverse_lazy("accounts:settings") + + def get(self, request, *args, **kwargs): + response = super().get(request, *args, **kwargs) + + user = request.user + task_active = cache.get(f"{user.email}-reddit-refresh") + + if not task_active: + RedditTokenTask.delay(user.pk) + messages.success(request, _("Access token is being retrieved")) + cache.set(f"{user.email}-reddit-refresh", 1, 300) + return response + + messages.error(request, _("Unable to retrieve token")) + return response diff --git a/src/newsreader/accounts/views/password.py b/src/newsreader/accounts/views/password.py new file mode 100644 index 0000000..e9e0aa3 --- /dev/null +++ b/src/newsreader/accounts/views/password.py @@ -0,0 +1,37 @@ +from django.contrib.auth import views as django_views +from django.urls import reverse_lazy + +from newsreader.news.collection.reddit import ( + get_reddit_access_token, + get_reddit_authorization_url, +) + + +# PasswordResetView sends the mail +# PasswordResetDoneView shows a success message for the above +# PasswordResetConfirmView checks the link the user clicked and +# prompts for a new password +# PasswordResetCompleteView shows a success message for the above +class PasswordResetView(django_views.PasswordResetView): + template_name = "password-reset/password-reset.html" + subject_template_name = "password-reset/password-reset-subject.txt" + email_template_name = "password-reset/password-reset-email.html" + success_url = reverse_lazy("accounts:password-reset-done") + + +class PasswordResetDoneView(django_views.PasswordResetDoneView): + template_name = "password-reset/password-reset-done.html" + + +class PasswordResetConfirmView(django_views.PasswordResetConfirmView): + template_name = "password-reset/password-reset-confirm.html" + success_url = reverse_lazy("accounts:password-reset-complete") + + +class PasswordResetCompleteView(django_views.PasswordResetCompleteView): + template_name = "password-reset/password-reset-complete.html" + + +class PasswordChangeView(django_views.PasswordChangeView): + template_name = "accounts/views/password-change.html" + success_url = reverse_lazy("accounts:settings") diff --git a/src/newsreader/accounts/views/registration.py b/src/newsreader/accounts/views/registration.py new file mode 100644 index 0000000..597aa9a --- /dev/null +++ b/src/newsreader/accounts/views/registration.py @@ -0,0 +1,59 @@ +from django.shortcuts import render +from django.urls import reverse_lazy +from django.views.generic import TemplateView + +from registration.backends.default import views as registration_views + +from newsreader.news.collection.reddit import ( + get_reddit_access_token, + get_reddit_authorization_url, +) + + +# RegistrationView shows a registration form and sends the email +# RegistrationCompleteView shows after filling in the registration form +# ActivationView is send within the activation email and activates the account +# ActivationCompleteView shows the success screen when activation was succesful +# ActivationResendView can be used when activation links are expired +# RegistrationClosedView shows when registration is disabled +class RegistrationView(registration_views.RegistrationView): + disallowed_url = reverse_lazy("accounts:register-closed") + template_name = "registration/registration_form.html" + success_url = reverse_lazy("accounts:register-complete") + + +class RegistrationCompleteView(TemplateView): + template_name = "registration/registration_complete.html" + + +class RegistrationClosedView(TemplateView): + template_name = "registration/registration_closed.html" + + +# Redirects or renders failed activation template +class ActivationView(registration_views.ActivationView): + template_name = "registration/activation_failure.html" + + def get_success_url(self, user): + return ("accounts:activate-complete", (), {}) + + +class ActivationCompleteView(TemplateView): + template_name = "registration/activation_complete.html" + + +# Renders activation form resend or resend_activation_complete +class ActivationResendView(registration_views.ResendActivationView): + template_name = "registration/activation_resend_form.html" + + def render_form_submitted_template(self, form): + """ + Renders resend activation complete template with the submitted email. + + """ + email = form.cleaned_data["email"] + context = {"email": email} + + return render( + self.request, "registration/activation_resend_complete.html", context + ) diff --git a/src/newsreader/accounts/views/settings.py b/src/newsreader/accounts/views/settings.py new file mode 100644 index 0000000..1fdff3b --- /dev/null +++ b/src/newsreader/accounts/views/settings.py @@ -0,0 +1,50 @@ +from django.core.cache import cache +from django.urls import reverse_lazy +from django.views.generic.edit import FormView, ModelFormMixin + +from newsreader.accounts.forms import UserSettingsForm +from newsreader.accounts.models import User +from newsreader.news.collection.reddit import ( + get_reddit_access_token, + get_reddit_authorization_url, +) + + +class SettingsView(ModelFormMixin, FormView): + template_name = "accounts/views/settings.html" + success_url = reverse_lazy("accounts:settings") + form_class = UserSettingsForm + model = User + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + return super().get(request, *args, **kwargs) + + def get_object(self, **kwargs): + return self.request.user + + def get_context_data(self, **kwargs): + user = self.request.user + + reddit_authorization_url = None + reddit_refresh_url = None + reddit_task_active = cache.get(f"{user.email}-reddit-refresh") + + if ( + user.reddit_refresh_token + and not user.reddit_access_token + and not reddit_task_active + ): + reddit_refresh_url = reverse_lazy("accounts:reddit-refresh") + + if not user.reddit_refresh_token: + reddit_authorization_url = get_reddit_authorization_url(user) + + return { + **super().get_context_data(**kwargs), + "reddit_authorization_url": reddit_authorization_url, + "reddit_refresh_url": reddit_refresh_url, + } + + def get_form_kwargs(self): + return {**super().get_form_kwargs(), "instance": self.request.user}