Files
hamprint/apps/accounts/views.py

69 lines
2.5 KiB
Python

"""Local account views -- the ones allauth doesn't ship.
Today: just `close_account` ("permanently delete this user"). Logout is
allauth's; we override its template, not its view.
"""
from __future__ import annotations
from django.contrib import messages
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required
from django.db import transaction
from django.http import HttpResponseForbidden
from django.shortcuts import redirect, render
from django.views.decorators.http import require_http_methods
from apps.submissions.models import Submission
@login_required
@require_http_methods(["GET", "POST"])
def close_account(request):
"""Permanently delete the signed-in user and all of their submissions.
GET -> render a "are you sure?" confirmation page, showing how many of
their submissions will go with the user.
POST -> delete the rows, log the user out, redirect to the dashboard.
Refuses staff users (`is_staff=True`): they'd be locking themselves
(and possibly the only operator) out of /admin/ with no recourse, so
that path requires another operator to remove the row via
/admin/auth/user/ instead.
Why delete the submissions too: `Submission.submitted_by` uses
`on_delete=SET_NULL`, but the `CheckConstraint` on the model requires
that EITHER `submitted_by` OR `guest_email` is non-null. OAuth-created
submissions have `guest_email=NULL`, so SET_NULL would violate the
constraint at delete time. Simpler + matches user expectation of
"delete my account": wipe the rows wholesale. The `post_delete` signal
in `apps/submissions/signals.py` unlinks the uploaded STLs at the
same time.
"""
if request.user.is_staff:
return HttpResponseForbidden(
"Staff users cannot close their own account from here. "
"Ask another operator to remove the row via /admin/auth/user/."
)
if request.method == "POST":
user = request.user
username = user.get_username()
with transaction.atomic():
Submission.objects.filter(submitted_by=user).delete()
logout(request)
user.delete()
messages.info(
request,
f"Account {username} and all of your prints have been "
f"permanently deleted.",
)
return redirect("dashboard:index")
submission_count = Submission.objects.filter(submitted_by=request.user).count()
return render(
request,
"account/close.html",
{"submission_count": submission_count},
)