mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
feat(FastAPI): add /pkgbase/{name}/request (post)
This change implements the FastAPI version of the /pkgbase/{name}/request form's action. Changes from PHP: - Additional errors are now displayed for the **merge_into** field, which are only displayed when the Merge type is selected. - If the **merge_into** field is empty, a new error is displayed: 'The "Merge into" field must not be empty.' - If the **merge_into** field is given the name of a package base which does not exist, a new error is displayed: "The package base you want to merge into does not exist." - If the **merge_into** field is given the name of the package base that a request is being created for, a new error is displayed: "You cannot merge a package base into itself." - When an error is encountered, users are now brought back to the request form which they submitted and an error is displayed at the top of the page. - If an invalid type is provided, users are returned to a BAD_REQUEST status rendering of the request form. Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
ad8369395e
commit
1c031638c6
4 changed files with 247 additions and 1 deletions
|
@ -20,6 +20,12 @@ class RequestType(Base):
|
|||
name = self.Name
|
||||
return name[0].upper() + name[1:]
|
||||
|
||||
def title(self) -> str:
|
||||
return self.name_display()
|
||||
|
||||
def __getitem__(self, n: int) -> str:
|
||||
return self.Name[n]
|
||||
|
||||
|
||||
DELETION_ID = db.query(RequestType, RequestType.Name == DELETION).first().ID
|
||||
ORPHAN_ID = db.query(RequestType, RequestType.Name == ORPHAN).first().ID
|
||||
|
|
|
@ -582,3 +582,72 @@ async def package_request(request: Request, name: str):
|
|||
|
||||
context["pkgbase"] = pkgbase
|
||||
return render_template(request, "pkgbase/request.html", context)
|
||||
|
||||
|
||||
@router.post("/pkgbase/{name}/request")
|
||||
@auth_required(True)
|
||||
async def pkgbase_request_post(request: Request, name: str,
|
||||
type: str = Form(...),
|
||||
merge_into: str = Form(default=None),
|
||||
comments: str = Form(default=str())):
|
||||
pkgbase = get_pkg_or_base(name, PackageBase)
|
||||
|
||||
# Create our render context.
|
||||
context = make_context(request, "Submit Request")
|
||||
context["pkgbase"] = pkgbase
|
||||
if type not in {"deletion", "merge", "orphan"}:
|
||||
# In the case that someone crafted a POST request with an invalid
|
||||
# type, just return them to the request form with BAD_REQUEST status.
|
||||
return render_template(request, "pkgbase/request.html", context,
|
||||
status_code=HTTPStatus.BAD_REQUEST)
|
||||
|
||||
if not comments:
|
||||
context["errors"] = ["The comment field must not be empty."]
|
||||
return render_template(request, "pkgbase/request.html", context)
|
||||
|
||||
if type == "merge":
|
||||
# Perform merge-related checks.
|
||||
if not merge_into:
|
||||
# TODO: This error needs to be translated.
|
||||
context["errors"] = ['The "Merge into" field must not be empty.']
|
||||
return render_template(request, "pkgbase/request.html", context)
|
||||
|
||||
target = db.query(PackageBase).filter(
|
||||
PackageBase.Name == merge_into
|
||||
).first()
|
||||
if not target:
|
||||
# TODO: This error needs to be translated.
|
||||
context["errors"] = [
|
||||
"The package base you want to merge into does not exist."
|
||||
]
|
||||
return render_template(request, "pkgbase/request.html", context)
|
||||
|
||||
if target.ID == pkgbase.ID:
|
||||
# TODO: This error needs to be translated.
|
||||
context["errors"] = [
|
||||
"You cannot merge a package base into itself."
|
||||
]
|
||||
return render_template(request, "pkgbase/request.html", context)
|
||||
|
||||
# All good. Create a new PackageRequest based on the given type.
|
||||
now = int(datetime.utcnow().timestamp())
|
||||
reqtype = db.query(RequestType, RequestType.Name == type).first()
|
||||
conn = db.ConnectionExecutor(db.get_engine().raw_connection())
|
||||
notify_ = None
|
||||
with db.begin():
|
||||
pkgreq = db.create(PackageRequest, RequestType=reqtype, RequestTS=now,
|
||||
PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
|
||||
MergeBaseName=merge_into, User=request.user,
|
||||
Comments=comments, ClosureComment=str())
|
||||
|
||||
# Prepare notification object.
|
||||
notify_ = notify.RequestOpenNotification(
|
||||
conn, request.user.ID, pkgreq.ID, reqtype,
|
||||
pkgreq.PackageBase.ID, merge_into=merge_into or None)
|
||||
|
||||
# Send the notification now that we're out of the DB scope.
|
||||
notify_.send()
|
||||
|
||||
# Redirect the submitting user to /packages.
|
||||
return RedirectResponse("/packages",
|
||||
status_code=int(HTTPStatus.SEE_OTHER))
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
{% extends "partials/layout.html" %}
|
||||
|
||||
{% block pageContent %}
|
||||
{% if errors %}
|
||||
<ul class="errorlist">
|
||||
{% for error in errors %}
|
||||
<li>{{ error | tr }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<div class="box">
|
||||
<h2>{{ "Submit Request" | tr }}: {{ pkgbase.Name }}</h2>
|
||||
|
||||
<p>
|
||||
{{ "Use this form to file a request against package base "
|
||||
"%s%s%s which includes the following packages:"
|
||||
|
@ -15,7 +24,8 @@
|
|||
</ul>
|
||||
|
||||
{# Request form #}
|
||||
<form id="request-form" action="/pkgbase/{{ pkgbase.Name }}/request">
|
||||
<form id="request-form" action="/pkgbase/{{ pkgbase.Name }}/request"
|
||||
method="post">
|
||||
<fieldset>
|
||||
<p>
|
||||
<label for="id_type">{{ "Request type" | tr }}:</label>
|
||||
|
|
|
@ -1420,3 +1420,164 @@ def test_pkgbase_request(client: TestClient, user: User, package: Package):
|
|||
with client as request:
|
||||
resp = request.get(endpoint, cookies=cookies)
|
||||
assert resp.status_code == int(HTTPStatus.OK)
|
||||
|
||||
|
||||
def test_pkgbase_request_post_deletion(client: TestClient, user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "deletion",
|
||||
"comments": "We want to delete this."
|
||||
}, cookies=cookies, allow_redirects=False)
|
||||
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
|
||||
|
||||
pkgreq = db.query(PackageRequest).filter(
|
||||
PackageRequest.PackageBaseID == package.PackageBase.ID
|
||||
).first()
|
||||
assert pkgreq is not None
|
||||
assert pkgreq.RequestType.Name == "deletion"
|
||||
assert pkgreq.PackageBaseName == package.PackageBase.Name
|
||||
assert pkgreq.Comments == "We want to delete this."
|
||||
|
||||
|
||||
def test_pkgbase_request_post_orphan(client: TestClient, user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "orphan",
|
||||
"comments": "We want to disown this."
|
||||
}, cookies=cookies, allow_redirects=False)
|
||||
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
|
||||
|
||||
pkgreq = db.query(PackageRequest).filter(
|
||||
PackageRequest.PackageBaseID == package.PackageBase.ID
|
||||
).first()
|
||||
assert pkgreq is not None
|
||||
assert pkgreq.RequestType.Name == "orphan"
|
||||
assert pkgreq.PackageBaseName == package.PackageBase.Name
|
||||
assert pkgreq.Comments == "We want to disown this."
|
||||
|
||||
|
||||
def test_pkgbase_request_post_merge(client: TestClient, user: User,
|
||||
package: Package):
|
||||
with db.begin():
|
||||
pkgbase2 = db.create(PackageBase, Name="new-pkgbase",
|
||||
Submitter=user, Maintainer=user, Packager=user)
|
||||
target = db.create(Package, PackageBase=pkgbase2,
|
||||
Name=pkgbase2.Name, Version="1.0.0")
|
||||
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "merge",
|
||||
"merge_into": target.PackageBase.Name,
|
||||
"comments": "We want to merge this."
|
||||
}, cookies=cookies, allow_redirects=False)
|
||||
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
|
||||
|
||||
pkgreq = db.query(PackageRequest).filter(
|
||||
PackageRequest.PackageBaseID == package.PackageBase.ID
|
||||
).first()
|
||||
assert pkgreq is not None
|
||||
assert pkgreq.RequestType.Name == "merge"
|
||||
assert pkgreq.PackageBaseName == package.PackageBase.Name
|
||||
assert pkgreq.MergeBaseName == target.PackageBase.Name
|
||||
assert pkgreq.Comments == "We want to merge this."
|
||||
|
||||
|
||||
def test_pkgbase_request_post_not_found(client: TestClient, user: User):
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post("/pkgbase/fake/request", data={
|
||||
"type": "fake"
|
||||
}, cookies=cookies)
|
||||
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
|
||||
|
||||
|
||||
def test_pkgbase_request_post_invalid_type(client: TestClient,
|
||||
user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={"type": "fake"}, cookies=cookies)
|
||||
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
|
||||
|
||||
|
||||
def test_pkgbase_request_post_no_comment_error(client: TestClient,
|
||||
user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "deletion",
|
||||
"comments": "" # An empty comment field causes an error.
|
||||
}, cookies=cookies)
|
||||
assert resp.status_code == int(HTTPStatus.OK)
|
||||
|
||||
root = parse_root(resp.text)
|
||||
error = root.xpath('//ul[@class="errorlist"]/li')[0]
|
||||
expected = "The comment field must not be empty."
|
||||
assert error.text.strip() == expected
|
||||
|
||||
|
||||
def test_pkgbase_request_post_merge_not_found_error(client: TestClient,
|
||||
user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "merge",
|
||||
"merge_into": "fake", # There is no PackageBase.Name "fake"
|
||||
"comments": "We want to merge this."
|
||||
}, cookies=cookies, allow_redirects=False)
|
||||
assert resp.status_code == int(HTTPStatus.OK)
|
||||
|
||||
root = parse_root(resp.text)
|
||||
error = root.xpath('//ul[@class="errorlist"]/li')[0]
|
||||
expected = "The package base you want to merge into does not exist."
|
||||
assert error.text.strip() == expected
|
||||
|
||||
|
||||
def test_pkgbase_request_post_merge_no_merge_into_error(client: TestClient,
|
||||
user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "merge",
|
||||
"merge_into": "", # There is no PackageBase.Name "fake"
|
||||
"comments": "We want to merge this."
|
||||
}, cookies=cookies, allow_redirects=False)
|
||||
assert resp.status_code == int(HTTPStatus.OK)
|
||||
|
||||
root = parse_root(resp.text)
|
||||
error = root.xpath('//ul[@class="errorlist"]/li')[0]
|
||||
expected = 'The "Merge into" field must not be empty.'
|
||||
assert error.text.strip() == expected
|
||||
|
||||
|
||||
def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User,
|
||||
package: Package):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
resp = request.post(endpoint, data={
|
||||
"type": "merge",
|
||||
"merge_into": package.PackageBase.Name,
|
||||
"comments": "We want to merge this."
|
||||
}, cookies=cookies, allow_redirects=False)
|
||||
assert resp.status_code == int(HTTPStatus.OK)
|
||||
|
||||
root = parse_root(resp.text)
|
||||
error = root.xpath('//ul[@class="errorlist"]/li')[0]
|
||||
expected = "You cannot merge a package base into itself."
|
||||
assert error.text.strip() == expected
|
||||
|
|
Loading…
Add table
Reference in a new issue