feat: GET|POST /account/{name}/delete

Closes #348

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2022-09-29 17:43:26 -07:00
parent 1180565d0c
commit 8657fd336e
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
6 changed files with 226 additions and 4 deletions

View file

@ -14,7 +14,7 @@ class PackageVote(Base):
User = relationship(
_User,
backref=backref("package_votes", lazy="dynamic"),
backref=backref("package_votes", lazy="dynamic", cascade="all, delete"),
foreign_keys=[__table__.c.UsersID],
)

View file

@ -13,7 +13,7 @@ class Session(Base):
User = relationship(
_User,
backref=backref("session", uselist=False),
backref=backref("session", cascade="all, delete", uselist=False),
foreign_keys=[__table__.c.UsersID],
)

View file

@ -3,13 +3,13 @@ import typing
from http import HTTPStatus
from typing import Any
from fastapi import APIRouter, Form, Request
from fastapi import APIRouter, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import and_, or_
import aurweb.config
from aurweb import cookies, db, l10n, logging, models, util
from aurweb.auth import account_type_required, requires_auth, requires_guest
from aurweb.auth import account_type_required, creds, requires_auth, requires_guest
from aurweb.captcha import get_captcha_salts
from aurweb.exceptions import ValidationError, handle_form_exceptions
from aurweb.l10n import get_translator_for_request
@ -598,6 +598,78 @@ async def accounts_post(
return render_template(request, "account/index.html", context)
@router.get("/account/{name}/delete")
@requires_auth
async def account_delete(request: Request, name: str):
user = db.query(models.User).filter(models.User.Username == name).first()
if not user:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
has_cred = request.user.has_credential(creds.ACCOUNT_EDIT, approved=[user])
if not has_cred:
_ = l10n.get_translator_for_request(request)
raise HTTPException(
detail=_("You do not have permission to edit this account."),
status_code=HTTPStatus.UNAUTHORIZED,
)
context = make_context(request, "Accounts")
context["name"] = name
return render_template(request, "account/delete.html", context)
@db.async_retry_deadlock
@router.post("/account/{name}/delete")
@handle_form_exceptions
@requires_auth
async def account_delete_post(
request: Request,
name: str,
passwd: str = Form(default=str()),
confirm: bool = Form(default=False),
):
user = db.query(models.User).filter(models.User.Username == name).first()
if not user:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
has_cred = request.user.has_credential(creds.ACCOUNT_EDIT, approved=[user])
if not has_cred:
_ = l10n.get_translator_for_request(request)
raise HTTPException(
detail=_("You do not have permission to edit this account."),
status_code=HTTPStatus.UNAUTHORIZED,
)
context = make_context(request, "Accounts")
context["name"] = name
confirm = util.strtobool(confirm)
if not confirm:
context["errors"] = [
"The account has not been deleted, check the confirmation checkbox."
]
return render_template(
request,
"account/delete.html",
context,
status_code=HTTPStatus.BAD_REQUEST,
)
if not request.user.valid_password(passwd):
context["errors"] = ["Invalid password."]
return render_template(
request,
"account/delete.html",
context,
status_code=HTTPStatus.BAD_REQUEST,
)
with db.begin():
db.delete(user)
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
def render_terms_of_service(request: Request, context: dict, terms: typing.Iterable):
if not terms:
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)