Changeset View
Changeset View
Standalone View
Standalone View
bid_main/views/normal_pages.py
| """Normal stuff, like index, profile editing, etc. | """Normal stuff, like index, profile editing, etc. | ||||
| No error handlers, no usually-one-off things like registration and | No error handlers, no usually-one-off things like registration and | ||||
| email confirmation. | email confirmation. | ||||
| """ | """ | ||||
| import logging | import logging | ||||
| import urllib.parse | import urllib.parse | ||||
| from django.conf import settings | from django.conf import settings | ||||
| from django.contrib.auth import views as auth_views, logout | |||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.contrib.auth import views as auth_views | |||||
| from django.db.models import Count | from django.db.models import Count | ||||
| from django.http import HttpResponseRedirect | from django.http import HttpResponseRedirect | ||||
| from django.shortcuts import resolve_url | from django.shortcuts import resolve_url, render | ||||
| from django.urls import reverse_lazy | from django.urls import reverse_lazy | ||||
| from django.utils import timezone | from django.utils import timezone | ||||
| from django.utils.decorators import method_decorator | from django.utils.decorators import method_decorator | ||||
| from django.views.decorators.debug import sensitive_post_parameters | |||||
| from django.views.decorators.csrf import csrf_exempt | |||||
| from django.views.decorators.cache import never_cache | from django.views.decorators.cache import never_cache | ||||
| from django.views.decorators.csrf import csrf_exempt | |||||
| from django.views.decorators.debug import sensitive_post_parameters | |||||
| from django.views.generic import TemplateView, FormView | from django.views.generic import TemplateView, FormView | ||||
| from django.views.generic.edit import UpdateView | from django.views.generic.edit import UpdateView | ||||
| import loginas.utils | import loginas.utils | ||||
| import oauth2_provider.models as oauth2_models | import oauth2_provider.models as oauth2_models | ||||
| from .. import forms | from .. import forms | ||||
| from ..models import User | from ..models import User | ||||
| from . import mixins | from . import mixins | ||||
| ▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | ): | ||||
| def get_form_kwargs(self): | def get_form_kwargs(self): | ||||
| kwargs = super().get_form_kwargs() | kwargs = super().get_form_kwargs() | ||||
| switch_to = self.kwargs.get("switch_to") | switch_to = self.kwargs.get("switch_to") | ||||
| if switch_to: | if switch_to: | ||||
| kwargs["initial"] = {**kwargs.get("initial", {}), "username": switch_to} | kwargs["initial"] = {**kwargs.get("initial", {}), "username": switch_to} | ||||
| return kwargs | return kwargs | ||||
| class ApplicationTokenView(mixins.PageIdMixin, LoginRequiredMixin, FormView): | class GetAppsMixin: | ||||
| page_id = "auth_tokens" | """Retrieve user applications.""" | ||||
| template_name = "bid_main/auth_tokens.html" | |||||
| form_class = forms.AppRevokeTokensForm | |||||
| success_url = reverse_lazy("bid_main:auth_tokens") | |||||
| log = logging.getLogger(f"{__name__}.ApplicationTokenView") | |||||
| def get(self, request, *args, **kwargs): | |||||
| ctx = self.get_context_data(**kwargs) | |||||
| def get_apps(self, request): | |||||
| tokens_per_app = list( | tokens_per_app = list( | ||||
| request.user.bid_main_oauth2accesstoken.values("application") | request.user.bid_main_oauth2accesstoken.values("application") | ||||
| .annotate(Count("id")) | .annotate(Count("id")) | ||||
| .order_by() | .order_by() | ||||
| ) | ) | ||||
| app_ids = {tpa["application"] for tpa in tokens_per_app} | app_ids = {tpa["application"] for tpa in tokens_per_app} | ||||
| app_model = oauth2_models.get_application_model() | app_model = oauth2_models.get_application_model() | ||||
| apps = app_model.objects.filter(id__in=app_ids).order_by("name") | return app_model.objects.filter(id__in=app_ids).order_by("name") | ||||
| ctx["apps"] = apps | |||||
| class ApplicationTokenView(mixins.PageIdMixin, LoginRequiredMixin, GetAppsMixin, FormView): | |||||
| page_id = "auth_tokens" | |||||
| template_name = "bid_main/auth_tokens.html" | |||||
| form_class = forms.AppRevokeTokensForm | |||||
| success_url = reverse_lazy("bid_main:auth_tokens") | |||||
| log = logging.getLogger(f"{__name__}.ApplicationTokenView") | |||||
| def get(self, request, *args, **kwargs): | |||||
| ctx = self.get_context_data(**kwargs) | |||||
| ctx["apps"] = self.get_apps(request) | |||||
| return self.render_to_response(ctx) | return self.render_to_response(ctx) | ||||
| def form_valid(self, form): | def form_valid(self, form): | ||||
| user = self.request.user | user = self.request.user | ||||
| app_id = form.cleaned_data["app_id"] | app_id = form.cleaned_data["app_id"] | ||||
| self.log.info( | self.log.info( | ||||
| "Revoking all oauth tokens for user %s, application %d", user, app_id | "Revoking all oauth tokens for user %s, application %d", user, app_id | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | def form_valid(self, form): | ||||
| object_id=self.request.user.id, | object_id=self.request.user.id, | ||||
| object_repr=str(self.request.user), | object_repr=str(self.request.user), | ||||
| action_flag=ADDITION, | action_flag=ADDITION, | ||||
| change_message=f"Agreed to privacy policy dated {settings.PPDATE}", | change_message=f"Agreed to privacy policy dated {settings.PPDATE}", | ||||
| ) | ) | ||||
| next_url = form.cleaned_data["next_url"] or self.default_success_url | next_url = form.cleaned_data["next_url"] or self.default_success_url | ||||
| return HttpResponseRedirect(next_url) | return HttpResponseRedirect(next_url) | ||||
| class DeleteUserView( | |||||
| mixins.RedirectToPrivacyAgreeMixin, LoginRequiredMixin, GetAppsMixin, FormView | |||||
| ): | |||||
| template_name = "bid_main/delete_user.html" | |||||
| form_class = forms.DeleteForm | |||||
| def get_context_data(self, **kwargs): | |||||
| ctx = super().get_context_data(**kwargs) | |||||
| ctx["apps"] = self.get_apps(self.request) | |||||
| return ctx | |||||
| def form_valid(self, form, **kwargs): | |||||
| """Handle valid form data that has been POSTed.""" | |||||
| user = self.request.user | |||||
| if not user.date_deletion_requested: | |||||
| user.date_deletion_requested = timezone.now() | |||||
| else: | |||||
| # This should never happen, but if it does, keep the original date | |||||
| log.error( | |||||
| "Received a deletion request for pk=%s who already requested it at %s", | |||||
| user.pk, | |||||
| user.date_deletion_requested, | |||||
| ) | |||||
| user.is_active = False | |||||
| user.save(update_fields=["date_deletion_requested", "is_active"]) | |||||
| logout(self.request) | |||||
| # TODO(anna): delete **all** sessions of this user, maybe in a periodic cleanup | |||||
| log.warning("Deletion request for pk=%s received", user.pk) | |||||
| ctx = {"success_deletion_requested": True} | |||||
| return render(self.request, "bid_main/delete_user/confirm.html", context=ctx) | |||||