fix(fastapi): remove trailing slashes from fastapi-driven links

With our FastAPI server, trailing slashes causes a 307 redirect
which ends up redirecting users to routes which do not contain
trailing slashes. This removes trailing slashes from our templates
where FastAPI is concerned to avoid unnecessary redirects.

There may still be links or usages around which have unnecessary
usages of a trailing slash; please keep a look out for these and
remove them where possible.

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-10-18 22:25:40 -07:00
parent e05cfc3375
commit 267f2cb2c4
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
14 changed files with 58 additions and 58 deletions

View file

@ -590,8 +590,8 @@ async def account(request: Request, username: str):
return render_template(request, "account/show.html", context)
@router.get("/accounts/")
@auth_required(True, redirect="/accounts/")
@router.get("/accounts")
@auth_required(True, redirect="/accounts")
@account_type_required({account_type.TRUSTED_USER,
account_type.DEVELOPER,
account_type.TRUSTED_USER_AND_DEV})
@ -600,8 +600,8 @@ async def accounts(request: Request):
return render_template(request, "account/search.html", context)
@router.post("/accounts/")
@auth_required(True, redirect="/accounts/")
@router.post("/accounts")
@auth_required(True, redirect="/accounts")
@account_type_required({account_type.TRUSTED_USER,
account_type.DEVELOPER,
account_type.TRUSTED_USER_AND_DEV})

View file

@ -6,7 +6,7 @@
{{ "Use this form to search existing accounts." | tr }}
<br />
<br />
<form class="account-search-form" action="/accounts/" method="post">
<form class="account-search-form" action="/accounts" method="post">
<fieldset>
<p>
<label for="id_username">{{ "Username" | tr }}:</label>

View file

@ -8,7 +8,7 @@
<div class="box">
<h2>{{ "Submit a proposal to vote on." | tr }}</h2>
<form action="/addvote/" method="post">
<form action="/addvote" method="post">
<p class="vote-applicant">
<label for="id_user">{{ "Applicant/TU" | tr }}</label>

View file

@ -6,7 +6,7 @@
<h2>AUR {% trans %}Login{% endtrans %}</h2>
{% if request.url.scheme == "http" and config.getboolean("options", "disable_http_login") %}
{% set https_login = url_base.replace("http://", "https://") + "/login/" %}
{% set https_login = url_base.replace("http://", "https://") + "/login" %}
<p>
{{ "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login."
| tr
@ -23,7 +23,7 @@
| format("<b>%s</b>" | format(request.user.Username))
| safe
}}
<a href="/logout/?next={{ next }}">[{% trans %}Logout{% endtrans %}]</a>
<a href="/logout?next={{ next }}">[{% trans %}Logout{% endtrans %}]</a>
</p>
{% else %}
<form method="post" action="/login?next={{ next }}">
@ -70,7 +70,7 @@
<p>
<input class="button" type="submit"
value="{% trans %}Login{% endtrans %}">
<a href="/passreset/">
<a href="/passreset">
[{% trans %}Forgot Password{% endtrans %}]
</a>
<input id="id_referer" type="hidden" name="referer"

View file

@ -40,7 +40,7 @@
<table class="results">
<tr>
<td align="left">
<form action="/accounts/" method="post">
<form action="/accounts" method="post">
<fieldset>
<input type="hidden" name="O"
value="{{ offset - pp }}" />
@ -59,7 +59,7 @@
</form>
</td>
<td align="right">
<form action="/accounts/" method="post">
<form action="/accounts" method="post">
<fieldset>
<input type="hidden" name="O"
value="{{ offset + pp }}" />

View file

@ -5,16 +5,16 @@
{% else %}
<li><a href="/">AUR {% trans %}Home{% endtrans %}</a></li>
{% endif %}
<li><a href="/packages/">{% trans %}Packages{% endtrans %}</a></li>
<li><a href="/packages">{% trans %}Packages{% endtrans %}</a></li>
{% if request.user.is_authenticated() %}
<li>
<a href="/requests/">
<a href="/requests">
{% trans %}Requests{% endtrans %}
</a>
</li>
{% if request.user.is_trusted_user() or request.user.is_developer() %}
<li>
<a href="/accounts/">
<a href="/accounts">
{% trans %}Accounts{% endtrans %}
</a>
</li>
@ -32,7 +32,7 @@
{% endif %}
<li>
<a href="/logout/?next={{ next }}">
<a href="/logout?next={{ next }}">
{% trans %}Logout{% endtrans %}
</a>
</li>
@ -43,7 +43,7 @@
</a>
</li>
<li>
<a href="/login/?next={{ next }}">
<a href="/login?next={{ next }}">
{% trans %}Login{% endtrans %}
</a>
</li>

View file

@ -10,7 +10,7 @@
<!-- Alternate resources -->
<link rel="alternate" type="application/rss+xml"
title="Newest Packages RSS" href="/rss/">
title="Newest Packages RSS" href="/rss">
<!-- Include local typeahead -->
<script type="text/javascript" src="/static/js/typeahead.js"></script>

View file

@ -26,7 +26,7 @@
</li>
{% if not out_of_date %}
<li>
<a href="/pkgbase/{{ pkgbase.Name }}/flag/">
<a href="/pkgbase/{{ pkgbase.Name }}/flag">
{{ "Flag package out-of-date" | tr }}
</a>
</li>
@ -52,14 +52,14 @@
{% endif %}
<li>
{% if not voted %}
<form action="/pkgbase/{{ pkgbase.Name }}/vote/" method="post">
<form action="/pkgbase/{{ pkgbase.Name }}/vote" method="post">
<input type="submit"
class="button text-button"
name="do_Vote"
value="{{ 'Vote for this package' | tr }}" />
</form>
{% else %}
<form action="/pkgbase/{{ pkgbase.Name }}/unvote/" method="post">
<form action="/pkgbase/{{ pkgbase.Name }}/unvote" method="post">
<input type="submit"
class="button text-button"
name="do_UnVote"
@ -69,7 +69,7 @@
</li>
<li>
{% if notified %}
<form action="/pkgbase/{{ pkgbase.Name }}/unnotify/" method="post">
<form action="/pkgbase/{{ pkgbase.Name }}/unnotify" method="post">
<input type="submit"
class="button text-button"
name="do_UnNotify"
@ -77,7 +77,7 @@
/>
</form>
{% else %}
<form action="/pkgbase/{{ pkgbase.Name }}/notify/" method="post">
<form action="/pkgbase/{{ pkgbase.Name }}/notify" method="post">
<input type="submit"
class="button text-button"
name="do_Notify"
@ -88,7 +88,7 @@
</li>
{% if request.user.has_credential('CRED_PKGBASE_EDIT_COMAINTAINERS', approved=[pkgbase.Maintainer]) %}
<li>
<a href="/pkgbase/{{ pkgbase.Name }}/comaintainers/">
<a href="/pkgbase/{{ pkgbase.Name }}/comaintainers">
{{ "Manage Co-Maintainers" | tr }}
</a>
</li>
@ -101,20 +101,20 @@
</li>
{% endif %}
<li>
<a href="/pkgbase/{{ pkgbase.Name }}/request/">
<a href="/pkgbase/{{ pkgbase.Name }}/request">
{{ "Submit Request" | tr }}
</a>
</li>
{% if request.user.has_credential("CRED_PKGBASE_DELETE") %}
<li>
<a href="/pkgbase/{{ pkgbase.Name }}/delete/">
<a href="/pkgbase/{{ pkgbase.Name }}/delete">
{{ "Delete Package" | tr }}
</a>
</li>
{% endif %}
{% if request.user.has_credential("CRED_PKGBASE_MERGE") %}
<li>
<a href="/pkgbase/{{ pkgbase.Name }}/merge/">
<a href="/pkgbase/{{ pkgbase.Name }}/merge">
{{ "Merge Package" | tr }}
</a>
</li>
@ -130,7 +130,7 @@
</li>
{% elif request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %}
<li>
<a href="/pkgbase/{{ pkgbase.Name }}/disown/">
<a href="/pkgbase/{{ pkgbase.Name }}/disown">
{{ "Disown Package" | tr }}
</a>
</li>

View file

@ -38,7 +38,7 @@
{% if request.user.has_credential("CRED_PKGBASE_SET_KEYWORDS", approved=[pkgbase.Maintainer]) %}
<td>
<form method="update"
action="/pkgbase/{{ pkgbase.Name }}/keywords/"
action="/pkgbase/{{ pkgbase.Name }}/keywords"
>
<div>
<input type="text"

View file

@ -3,7 +3,7 @@
<ul>
{% for result in packages %}
<li>
<a href="/packages/{{ result.Name }}/"
<a href="/packages/{{ result.Name }}"
title="{{ 'View packages details for' | tr }} {{ result.Name }}">
{{ result.Name }}
</a>

View file

@ -1,5 +1,5 @@
<div id="pkgsearch" class="widget">
<form id="pkgsearch-form" method="get" action="/packages/">
<form id="pkgsearch-form" method="get" action="/packages">
<fieldset>
<label for="pkgsearch-field">{{ "Package Search" | tr }}:</label>
<input type="hidden" name="O" value="0" />

View file

@ -5,7 +5,7 @@
(<a href="/packages/?SB=l&SO=d">{{ "more" | tr }}</a>)
</span>
</h3>
<a class="rss-icon latest" href="/rss/"
<a class="rss-icon latest" href="/rss"
title="AUR Latest Packages RSS Feed">
<img src="/static/images/rss.svg" alt="RSS Feed" />
</a>

View file

@ -4,7 +4,7 @@
{% if title == "Current Votes" %}
<ul class="admin-actions">
<li>
<a href="/addvote/">
<a href="/addvote">
{% trans %}Add Proposal{% endtrans %}
</a>
</li>

View file

@ -942,13 +942,13 @@ def test_get_account_unauthenticated():
def test_get_accounts(tu_user):
""" Test that we can GET request /accounts/ and receive
a form which can be used to POST /accounts/. """
""" Test that we can GET request /accounts and receive
a form which can be used to POST /accounts. """
sid = user.login(Request(), "testPassword")
cookies = {"AURSID": sid}
with client as request:
response = request.get("/accounts/", cookies=cookies)
response = request.get("/accounts", cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
parser = lxml.etree.HTMLParser()
@ -961,7 +961,7 @@ def test_get_accounts(tu_user):
assert len(form) == 1
form = next(iter(form))
assert form.attrib.get("method") == "post"
assert form.attrib.get("action") == "/accounts/"
assert form.attrib.get("action") == "/accounts"
def field(element):
""" Return the given element string as a valid
@ -1020,7 +1020,7 @@ def test_post_accounts(tu_user):
cookies = {"AURSID": sid}
with client as request:
response = request.post("/accounts/", cookies=cookies)
response = request.post("/accounts", cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1061,7 +1061,7 @@ def test_post_accounts_username(tu_user):
cookies = {"AURSID": sid}
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"U": user.Username})
assert response.status_code == int(HTTPStatus.OK)
@ -1093,14 +1093,14 @@ def test_post_accounts_account_type(tu_user):
# Expect no entries; we marked our only user as a User type.
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"T": "t"})
assert response.status_code == int(HTTPStatus.OK)
assert len(get_rows(response.text)) == 0
# So, let's also ensure that specifying "u" returns our user.
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"T": "u"})
assert response.status_code == int(HTTPStatus.OK)
@ -1119,7 +1119,7 @@ def test_post_accounts_account_type(tu_user):
).first()
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"T": "t"})
assert response.status_code == int(HTTPStatus.OK)
@ -1137,7 +1137,7 @@ def test_post_accounts_account_type(tu_user):
).first()
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"T": "d"})
assert response.status_code == int(HTTPStatus.OK)
@ -1155,7 +1155,7 @@ def test_post_accounts_account_type(tu_user):
).first()
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"T": "td"})
assert response.status_code == int(HTTPStatus.OK)
@ -1174,7 +1174,7 @@ def test_post_accounts_status(tu_user):
cookies = {"AURSID": sid}
with client as request:
response = request.post("/accounts/", cookies=cookies)
response = request.post("/accounts", cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1188,7 +1188,7 @@ def test_post_accounts_status(tu_user):
user.Suspended = True
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"S": True})
assert response.status_code == int(HTTPStatus.OK)
@ -1206,7 +1206,7 @@ def test_post_accounts_email(tu_user):
# Search via email.
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"E": user.Email})
assert response.status_code == int(HTTPStatus.OK)
@ -1220,7 +1220,7 @@ def test_post_accounts_realname(tu_user):
cookies = {"AURSID": sid}
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"R": user.RealName})
assert response.status_code == int(HTTPStatus.OK)
@ -1234,7 +1234,7 @@ def test_post_accounts_irc(tu_user):
cookies = {"AURSID": sid}
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"I": user.IRCNick})
assert response.status_code == int(HTTPStatus.OK)
@ -1259,14 +1259,14 @@ def test_post_accounts_sortby(tu_user):
# Show that "u" is the default search order, by username.
with client as request:
response = request.post("/accounts/", cookies=cookies)
response = request.post("/accounts", cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
assert len(rows) == 2
first_rows = rows
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"SB": "u"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1280,7 +1280,7 @@ def test_post_accounts_sortby(tu_user):
assert compare_text_values(0, first_rows, rows) is True
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"SB": "i"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1291,7 +1291,7 @@ def test_post_accounts_sortby(tu_user):
# Sort by "i" -> RealName.
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"SB": "r"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1307,7 +1307,7 @@ def test_post_accounts_sortby(tu_user):
# Fetch first_rows again with our new AccountType ordering.
with client as request:
response = request.post("/accounts/", cookies=cookies)
response = request.post("/accounts", cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
assert len(rows) == 2
@ -1315,7 +1315,7 @@ def test_post_accounts_sortby(tu_user):
# Sort by "t" -> AccountType.
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"SB": "t"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1334,7 +1334,7 @@ def test_post_accounts_pgp_key(tu_user):
# Search via PGPKey.
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"K": user.PGPKey})
assert response.status_code == int(HTTPStatus.OK)
@ -1360,7 +1360,7 @@ def test_post_accounts_paged(tu_user):
cookies = {"AURSID": sid}
with client as request:
response = request.post("/accounts/", cookies=cookies)
response = request.post("/accounts", cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@ -1386,7 +1386,7 @@ def test_post_accounts_paged(tu_user):
assert "disabled" not in page_next.attrib
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"O": 50}) # +50 offset.
assert response.status_code == int(HTTPStatus.OK)
@ -1401,7 +1401,7 @@ def test_post_accounts_paged(tu_user):
assert username.text.strip() == _user.Username
with client as request:
response = request.post("/accounts/", cookies=cookies,
response = request.post("/accounts", cookies=cookies,
data={"O": 101}) # Last page.
assert response.status_code == int(HTTPStatus.OK)