fix(templates): require valid User relationships for <a> usage

Previously, when the relationship was None, an <a> would still
wrap the None value erroneously. This addresses that for all
three user fields.

In addition, this commit adds direct testing for the
`templates/partials/packages/details.html` template.

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-12-31 01:02:40 -08:00
parent 278490e103
commit 53fabdfaea
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
2 changed files with 230 additions and 8 deletions

View file

@ -96,9 +96,9 @@
<tr>
<th>{{ "Submitter" | tr }}:</th>
<td>
{% if request.user.is_authenticated() %}
{% if request.user.is_authenticated() and pkgbase.Submitter %}
<a href="/account/{{ pkgbase.Submitter.Username }}">
{{ pkgbase.Submitter.Username | default("None" | tr) }}
{{ pkgbase.Submitter.Username }}
</a>
{% else %}
{{ pkgbase.Submitter.Username | default("None" | tr) }}
@ -108,9 +108,9 @@
<tr>
<th>{{ "Maintainer" | tr }}:</th>
<td>
{% if request.user.is_authenticated() %}
{% if request.user.is_authenticated() and pkgbase.Maintainer %}
<a href="/account/{{ pkgbase.Maintainer.Username }}">
{{ pkgbase.Maintainer.Username | default("None" | tr) }}
{{ pkgbase.Maintainer.Username }}
</a>
{% else %}
{{ pkgbase.Maintainer.Username | default("None" | tr) }}
@ -120,9 +120,9 @@
<tr>
<th>{{ "Last Packager" | tr }}:</th>
<td>
{% if request.user.is_authenticated() %}
{% if request.user.is_authenticated() and pkgbase.Packager %}
<a href="/account/{{ pkgbase.Packager.Username }}">
{{ pkgbase.Packager.Username | default("None" | tr) }}
{{ pkgbase.Packager.Username }}
</a>
{% else %}
{{ pkgbase.Packager.Username | default("None" | tr) }}

View file

@ -1,15 +1,27 @@
import re
from datetime import datetime
from typing import Any, Dict
import pytest
import aurweb.filters # noqa: F401
from aurweb import config, templates
from aurweb.templates import base_template, register_filter, register_function
from aurweb import config, db, templates
from aurweb.models import Package, PackageBase, User
from aurweb.models.account_type import USER_ID
from aurweb.models.license import License
from aurweb.models.package_license import PackageLicense
from aurweb.models.package_relation import PackageRelation
from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID
from aurweb.templates import base_template, make_context, register_filter, register_function
from aurweb.testing.html import parse_root
from aurweb.testing.requests import Request
from aurweb.util import as_timezone, number_format
from aurweb.util import timestamp_to_datetime as to_dt
GIT_CLONE_URI_ANON = "anon_%s"
GIT_CLONE_URI_PRIV = "priv_%s"
@register_filter("func")
@ -22,6 +34,51 @@ def function():
pass
def create_user(username: str) -> User:
with db.begin():
user = db.create(User, Username=username,
Email=f"{username}@example.org",
Passwd="testPassword",
AccountTypeID=USER_ID)
return user
def create_pkgrel(package: Package, reltype_id: int, relname: str) \
-> PackageRelation:
return db.create(PackageRelation,
Package=package,
RelTypeID=reltype_id,
RelName=relname)
@pytest.fixture
def user(db_test) -> User:
user = create_user("test")
yield user
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
now = int(datetime.utcnow().timestamp())
with db.begin():
pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=user,
SubmittedTS=now, ModifiedTS=now)
yield pkgbase
@pytest.fixture
def package(user: User, pkgbase: PackageBase) -> Package:
with db.begin():
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield pkg
def create_license(pkg: Package, license_name: str) -> PackageLicense:
lic = db.create(License, Name=license_name)
pkglic = db.create(PackageLicense, License=lic, Package=pkg)
return pkglic
def test_register_filter_exists_key_error():
""" Most instances of register_filter are tested through module
imports or template renders, so we only test failures here. """
@ -114,3 +171,168 @@ def test_pager():
stats = re.sub(r"\s{2,}", " ", stats[0].text.strip())
expected = f"{num_packages} packages found. Page 1 of 2."
assert stats == expected
def check_package_details(content: str, pkg: Package) -> None:
"""
Perform assertion checks against package details.
"""
pkgbase = pkg.PackageBase
root = parse_root(content)
pkginfo = root.xpath('//table[@id="pkginfo"]')[0]
rows = pkginfo.xpath("./tr")
# Check Git Clone URL.
git_clone_uris = rows[0].xpath("./td/a")
anon_uri, priv_uri = git_clone_uris
pkgbasename = pkgbase.Name
assert anon_uri.text.strip() == GIT_CLONE_URI_ANON % pkgbasename
assert priv_uri.text.strip() == GIT_CLONE_URI_PRIV % pkgbasename
# Check Package Base.
pkgbase_markup = rows[1].xpath("./td/a")[0]
assert pkgbase_markup.text.strip() == pkgbasename
# Check Description.
desc = rows[2].xpath("./td")[0]
assert desc.text.strip() == str(pkg.Description)
# Check URL, for which we have none. In this case, no <a> should
# be used since we have nothing to link.
url = rows[3].xpath("./td")[0]
assert url.text.strip() == str(pkg.URL)
# Check Keywords, which should be empty.
keywords = rows[4].xpath("./td/form/div/input")[0]
assert keywords.attrib["value"] == str()
i = 4
licenses = pkg.package_licenses.all()
if licenses:
i += 1
expected = ", ".join([p.License.Name for p in licenses])
license_markup = rows[i].xpath("./td")[0]
assert license_markup.text.strip() == expected
else:
assert "Licenses" not in content
provides = pkg.package_relations.filter(
PackageRelation.RelTypeID == PROVIDES_ID
).all()
if provides:
i += 1
expected = ", ".join([p.RelName for p in provides])
provides_markup = rows[i].xpath("./td")[0]
assert provides_markup.text.strip() == expected
else:
assert "Provides" not in content
replaces = pkg.package_relations.filter(
PackageRelation.RelTypeID == REPLACES_ID
).all()
if replaces:
i += 1
expected = ", ".join([r.RelName for r in replaces])
replaces_markup = rows[i].xpath("./td")[0]
assert replaces_markup.text.strip() == expected
else:
assert "Replaces" not in content
# Check Submitter.
selector = "./td" if not pkg.PackageBase.Submitter else "./td/a"
i += 1
submitter = rows[i].xpath(selector)[0]
assert submitter.text.strip() == str(pkg.PackageBase.Submitter)
# Check Maintainer.
selector = "./td" if not pkg.PackageBase.Maintainer else "./td/a"
i += 1
maintainer = rows[i].xpath(selector)[0]
assert maintainer.text.strip() == str(pkg.PackageBase.Maintainer)
# Check Packager.
selector = "./td" if not pkg.PackageBase.Packager else "./td/a"
i += 1
packager = rows[i].xpath(selector)[0]
assert packager.text.strip() == str(pkg.PackageBase.Packager)
# Check Votes.
i += 1
votes = rows[i].xpath("./td")[0]
assert votes.text.strip() == str(pkg.PackageBase.NumVotes)
# Check Popularity; for this package, a number_format of 6 places is used.
i += 1
pop = rows[i].xpath("./td")[0]
assert pop.text.strip() == number_format(0, 6)
# Check First Submitted
date_fmt = "%Y-%m-%d %H:%M"
i += 1
first_submitted = rows[i].xpath("./td")[0]
converted_dt = as_timezone(to_dt(pkg.PackageBase.SubmittedTS), "UTC")
expected = converted_dt.strftime(date_fmt)
assert first_submitted.text.strip() == expected
# Check Last Updated.
i += 1
last_updated = rows[i].xpath("./td")[0]
converted_dt = as_timezone(to_dt(pkg.PackageBase.ModifiedTS), "UTC")
expected = converted_dt.strftime(date_fmt)
assert last_updated.text.strip() == expected
def test_package_details(user: User, package: Package):
""" Test package details with most fields populated, but not all. """
request = Request(user=user, authenticated=True)
context = make_context(request, "Test Details")
context.update({
"request": request,
"git_clone_uri_anon": GIT_CLONE_URI_ANON,
"git_clone_uri_priv": GIT_CLONE_URI_PRIV,
"pkgbase": package.PackageBase,
"pkg": package
})
base = base_template("partials/packages/details.html")
body = base.render(context, show_package_details=True)
check_package_details(body, package)
def test_package_details_filled(user: User, package: Package):
""" Test package details with all fields populated. """
pkgbase = package.PackageBase
with db.begin():
# Setup Submitter and Packager; Maintainer is already set to `user`.
pkgbase.Submitter = pkgbase.Packager = user
# Create two licenses.
create_license(package, "TPL") # Testing Public License
create_license(package, "TPL2") # Testing Public License 2
# Add provides.
create_pkgrel(package, PROVIDES_ID, "test-provider")
# Add replaces.
create_pkgrel(package, REPLACES_ID, "test-replacement")
request = Request(user=user, authenticated=True)
context = make_context(request, "Test Details")
context.update({
"request": request,
"git_clone_uri_anon": GIT_CLONE_URI_ANON,
"git_clone_uri_priv": GIT_CLONE_URI_PRIV,
"pkgbase": package.PackageBase,
"pkg": package,
"licenses": package.package_licenses,
"provides": package.package_relations.filter(
PackageRelation.RelTypeID == PROVIDES_ID),
"replaces": package.package_relations.filter(
PackageRelation.RelTypeID == REPLACES_ID),
})
base = base_template("partials/packages/details.html")
body = base.render(context, show_package_details=True)
check_package_details(body, package)