diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py
index f806f054..b623ca10 100644
--- a/aurweb/routers/packages.py
+++ b/aurweb/routers/packages.py
@@ -950,6 +950,23 @@ async def pkgbase_disown_post(request: Request, name: str,
status_code=int(HTTPStatus.SEE_OTHER))
+@router.post("/pkgbase/{name}/adopt")
+@auth_required(True)
+async def pkgbase_adopt_post(request: Request, name: str):
+ pkgbase = get_pkg_or_base(name, PackageBase)
+
+ has_cred = request.user.has_credential("CRED_PKGBASE_ADOPT")
+ if has_cred or not pkgbase.Maintainer:
+ # If the user has credentials, they'll adopt the package regardless
+ # of maintainership. Otherwise, we'll promote the user to maintainer
+ # if no maintainer currently exists.
+ with db.begin():
+ pkgbase.Maintainer = 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):
diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html
index 2b26144e..dd83c84d 100644
--- a/templates/partials/packages/actions.html
+++ b/templates/partials/packages/actions.html
@@ -119,12 +119,23 @@
{% endif %}
- {% if request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %}
+ {% if not result.Maintainer %}
-
- {{ "Disown Package" | tr }}
-
+
+ {% else %}
+ {% if request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %}
+
+
+ {{ "Disown Package" | tr }}
+
+
+ {% endif %}
{% endif %}
diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py
index 7b9c520c..86949996 100644
--- a/test/test_packages_routes.py
+++ b/test/test_packages_routes.py
@@ -1849,6 +1849,39 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User,
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
+def test_pkgbase_adopt(client: TestClient, user: User, tu_user: User,
+ maintainer: User, package: Package):
+ # Unset the maintainer as if package is orphaned.
+ with db.begin():
+ package.PackageBase.Maintainer = None
+
+ pkgbasename = package.PackageBase.Name
+ cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
+ endpoint = f"/pkgbase/{pkgbasename}/adopt"
+
+ # Adopt the package base.
+ with client as request:
+ resp = request.post(endpoint, cookies=cookies, allow_redirects=False)
+ assert resp.status_code == int(HTTPStatus.SEE_OTHER)
+ assert package.PackageBase.Maintainer == maintainer
+
+ # Try to adopt it when it already has a maintainer; nothing changes.
+ user_cookies = {"AURSID": user.login(Request(), "testPassword")}
+ with client as request:
+ resp = request.post(endpoint, cookies=user_cookies,
+ allow_redirects=False)
+ assert resp.status_code == int(HTTPStatus.SEE_OTHER)
+ assert package.PackageBase.Maintainer == maintainer
+
+ # Steal the package as a TU.
+ tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
+ with client as request:
+ resp = request.post(endpoint, cookies=tu_cookies,
+ allow_redirects=False)
+ assert resp.status_code == int(HTTPStatus.SEE_OTHER)
+ assert package.PackageBase.Maintainer == tu_user
+
+
def test_pkgbase_delete_unauthorized(client: TestClient, user: User,
package: Package):
pkgbase = package.PackageBase