diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 40322785..4426d0be 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -940,3 +940,40 @@ async def pkgbase_disown_post(request: Request, name: str, disown_pkgbase(pkgbase, request.user) return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.get("/pkgbase/{name}/delete") +@auth_required(True) +async def pkgbase_delete_get(request: Request, name: str): + if not request.user.has_credential("CRED_PKGBASE_DELETE"): + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + context = make_context(request, "Package Deletion") + context["pkgbase"] = get_pkg_or_base(name, PackageBase) + return render_template(request, "packages/delete.html", context) + + +@router.post("/pkgbase/{name}/delete") +@auth_required(True) +async def pkgbase_delete_post(request: Request, name: str, + confirm: bool = Form(default=False)): + pkgbase = get_pkg_or_base(name, PackageBase) + + if not request.user.has_credential("CRED_PKGBASE_DELETE"): + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + if not confirm: + context = make_context(request, "Package Deletion") + context["pkgbase"] = pkgbase + context["errors"] = [("The selected packages have not been deleted, " + "check the confirmation checkbox.")] + return render_template(request, "packages/delete.html", context, + status_code=int(HTTPStatus.EXPECTATION_FAILED)) + + packages = pkgbase.packages.all() + for package in packages: + delete_package(request.user, package) + + return RedirectResponse("/packages", status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/packages/delete.html b/templates/packages/delete.html new file mode 100644 index 00000000..6e882d05 --- /dev/null +++ b/templates/packages/delete.html @@ -0,0 +1,56 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + + {% if errors %} + + {% endif %} + +
+

{{ "Delete Package" | tr }}: {{ pkgbase.Name }}

+ +

+ {{ + "Use this form to delete the package base %s%s%s and " + "the following packages from the AUR: " + | tr | format("", pkgbase.Name, "") | safe + }} +

+ + + +

+ {{ + "Deletion of a package is permanent. " + "Select the checkbox to confirm action." | tr + }} +

+ +
+
+

+ +

+ +

+ +

+
+
+ +
+{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index c9622431..1f258497 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1845,3 +1845,49 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, with client as request: resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_pkgbase_delete_unauthorized(client: TestClient, user: User, + package: Package): + pkgbase = package.PackageBase + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/delete" + + # Test GET. + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + # Test POST. + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + +def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package): + pkgbase = package.PackageBase + + # Test that the GET request works. + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/delete" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # Test that POST works and denies us because we haven't confirmed. + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.EXPECTATION_FAILED) + + # Test that we can actually delete the pkgbase. + with client as request: + resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # Let's assert that the package base record got removed. + record = db.query(PackageBase).filter( + PackageBase.Name == pkgbase.Name + ).first() + assert record is None