mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
feat: add paging to package depends & required by
This patch does not include a javascript implementating, but provides a pure HTML/HTTP method of paging through these lists. Also fixes erroneous limiting. We now use a hardcoded limit of 20 by default. Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
d8564e446b
commit
ed41a4fe19
7 changed files with 125 additions and 16 deletions
|
@ -214,7 +214,7 @@ def query_notified(query: List[models.Package],
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def pkg_required(pkgname: str, provides: List[str], limit: int) \
|
def pkg_required(pkgname: str, provides: List[str]) \
|
||||||
-> List[PackageDependency]:
|
-> List[PackageDependency]:
|
||||||
"""
|
"""
|
||||||
Get dependencies that match a string in `[pkgname] + provides`.
|
Get dependencies that match a string in `[pkgname] + provides`.
|
||||||
|
@ -227,8 +227,8 @@ def pkg_required(pkgname: str, provides: List[str], limit: int) \
|
||||||
targets = set([pkgname] + provides)
|
targets = set([pkgname] + provides)
|
||||||
query = db.query(PackageDependency).join(Package).filter(
|
query = db.query(PackageDependency).join(Package).filter(
|
||||||
PackageDependency.DepName.in_(targets)
|
PackageDependency.DepName.in_(targets)
|
||||||
).order_by(Package.Name.asc()).limit(limit)
|
).order_by(Package.Name.asc())
|
||||||
return query.all()
|
return query
|
||||||
|
|
||||||
|
|
||||||
@register_filter("source_uri")
|
@register_filter("source_uri")
|
||||||
|
|
|
@ -11,16 +11,25 @@ from aurweb.models.package_request import PENDING_ID, PackageRequest
|
||||||
from aurweb.models.package_vote import PackageVote
|
from aurweb.models.package_vote import PackageVote
|
||||||
from aurweb.scripts import notify
|
from aurweb.scripts import notify
|
||||||
from aurweb.templates import make_context as _make_context
|
from aurweb.templates import make_context as _make_context
|
||||||
|
from aurweb.templates import make_variable_context as _make_variable_context
|
||||||
|
|
||||||
|
|
||||||
def make_context(request: Request, pkgbase: PackageBase) -> Dict[str, Any]:
|
async def make_variable_context(request: Request, pkgbase: PackageBase) \
|
||||||
|
-> Dict[str, Any]:
|
||||||
|
ctx = await _make_variable_context(request, pkgbase.Name)
|
||||||
|
return make_context(request, pkgbase, ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def make_context(request: Request, pkgbase: PackageBase,
|
||||||
|
context: Dict[str, Any] = None) -> Dict[str, Any]:
|
||||||
""" Make a basic context for package or pkgbase.
|
""" Make a basic context for package or pkgbase.
|
||||||
|
|
||||||
:param request: FastAPI request
|
:param request: FastAPI request
|
||||||
:param pkgbase: PackageBase instance
|
:param pkgbase: PackageBase instance
|
||||||
:return: A pkgbase context without specific differences
|
:return: A pkgbase context without specific differences
|
||||||
"""
|
"""
|
||||||
context = _make_context(request, pkgbase.Name)
|
if not context:
|
||||||
|
context = _make_context(request, pkgbase.Name)
|
||||||
|
|
||||||
context["git_clone_uri_anon"] = config.get("options", "git_clone_uri_anon")
|
context["git_clone_uri_anon"] = config.get("options", "git_clone_uri_anon")
|
||||||
context["git_clone_uri_priv"] = config.get("options", "git_clone_uri_priv")
|
context["git_clone_uri_priv"] = config.get("options", "git_clone_uri_priv")
|
||||||
|
|
|
@ -2,7 +2,7 @@ from collections import defaultdict
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from fastapi import APIRouter, Form, Request, Response
|
from fastapi import APIRouter, Form, Query, Request, Response
|
||||||
|
|
||||||
import aurweb.filters # noqa: F401
|
import aurweb.filters # noqa: F401
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ async def packages_get(request: Request, context: Dict[str, Any],
|
||||||
context["O"] = offset
|
context["O"] = offset
|
||||||
|
|
||||||
# Limit PP to options.max_search_results
|
# Limit PP to options.max_search_results
|
||||||
max_search_results = aurweb.config.getint("options", "max_search_results")
|
max_search_results = config.getint("options", "max_search_results")
|
||||||
context["PP"] = per_page = min(per_page, max_search_results)
|
context["PP"] = per_page = min(per_page, max_search_results)
|
||||||
|
|
||||||
# Query search by.
|
# Query search by.
|
||||||
|
@ -123,7 +123,22 @@ async def packages(request: Request) -> Response:
|
||||||
|
|
||||||
|
|
||||||
@router.get("/packages/{name}")
|
@router.get("/packages/{name}")
|
||||||
async def package(request: Request, name: str) -> Response:
|
async def package(request: Request, name: str,
|
||||||
|
all_deps: bool = Query(default=False),
|
||||||
|
all_reqs: bool = Query(default=False)) -> Response:
|
||||||
|
"""
|
||||||
|
Get a package by name.
|
||||||
|
|
||||||
|
By default, we limit the number of depends and requires results
|
||||||
|
to 20. To bypass this and load all of them, which should be triggered
|
||||||
|
via a "Show more" link near the limited listing.
|
||||||
|
|
||||||
|
:param name: Package.Name
|
||||||
|
:param all_deps: Boolean indicating whether we should load all depends
|
||||||
|
:param all_reqs: Boolean indicating whether we should load all requires
|
||||||
|
:return: FastAPI Response
|
||||||
|
"""
|
||||||
|
|
||||||
# Get the Package.
|
# Get the Package.
|
||||||
pkg = get_pkg_or_base(name, models.Package)
|
pkg = get_pkg_or_base(name, models.Package)
|
||||||
pkgbase = pkg.PackageBase
|
pkgbase = pkg.PackageBase
|
||||||
|
@ -139,23 +154,41 @@ async def package(request: Request, name: str) -> Response:
|
||||||
rels_data["r"].append(rel)
|
rels_data["r"].append(rel)
|
||||||
|
|
||||||
# Add our base information.
|
# Add our base information.
|
||||||
context = pkgbaseutil.make_context(request, pkgbase)
|
context = await pkgbaseutil.make_variable_context(request, pkgbase)
|
||||||
|
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
"all_deps": all_deps,
|
||||||
|
"all_reqs": all_reqs
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
context["package"] = pkg
|
context["package"] = pkg
|
||||||
|
|
||||||
# Package sources.
|
# Package sources.
|
||||||
context["sources"] = pkg.package_sources.order_by(
|
context["sources"] = pkg.package_sources.order_by(
|
||||||
models.PackageSource.Source.asc()).all()
|
models.PackageSource.Source.asc()).all()
|
||||||
|
|
||||||
|
# Listing metadata.
|
||||||
|
context["max_listing"] = max_listing = 20
|
||||||
|
|
||||||
# Package dependencies.
|
# Package dependencies.
|
||||||
max_depends = config.getint("options", "max_depends")
|
deps = pkg.package_dependencies.order_by(
|
||||||
context["dependencies"] = pkg.package_dependencies.order_by(
|
|
||||||
models.PackageDependency.DepTypeID.asc(),
|
models.PackageDependency.DepTypeID.asc(),
|
||||||
models.PackageDependency.DepName.asc()
|
models.PackageDependency.DepName.asc()
|
||||||
).limit(max_depends).all()
|
)
|
||||||
|
context["depends_count"] = deps.count()
|
||||||
|
if not all_deps:
|
||||||
|
deps = deps.limit(max_listing)
|
||||||
|
context["dependencies"] = deps.all()
|
||||||
|
|
||||||
# Package requirements (other packages depend on this one).
|
# Package requirements (other packages depend on this one).
|
||||||
context["required_by"] = pkgutil.pkg_required(
|
reqs = pkgutil.pkg_required(
|
||||||
pkg.Name, [p.RelName for p in rels_data.get("p", [])], max_depends)
|
pkg.Name, [p.RelName for p in rels_data.get("p", [])])
|
||||||
|
context["reqs_count"] = reqs.count()
|
||||||
|
if not all_reqs:
|
||||||
|
reqs = reqs.limit(max_listing)
|
||||||
|
context["required_by"] = reqs.all()
|
||||||
|
|
||||||
context["licenses"] = pkg.package_licenses
|
context["licenses"] = pkg.package_licenses
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,8 @@ async def make_variable_context(request: Request, title: str, next: str = None):
|
||||||
for k, v in to_copy.items():
|
for k, v in to_copy.items():
|
||||||
context[k] = v
|
context[k] = v
|
||||||
|
|
||||||
|
context["q"] = dict(request.query_params)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2338,3 +2338,11 @@ msgstr ""
|
||||||
#: templates/partials/tu/proposal/details.html
|
#: templates/partials/tu/proposal/details.html
|
||||||
msgid "assigned"
|
msgid "assigned"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templaets/partials/packages/package_metadata.html
|
||||||
|
msgid "Show %d more"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/partials/packages/package_metadata.html
|
||||||
|
msgid "dependencies"
|
||||||
|
msgstr ""
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div id="pkgdeps" class="listing">
|
<div id="pkgdeps" class="listing">
|
||||||
<h3>{{ "Dependencies" | tr }} ({{ dependencies | length }})</h3>
|
<h3>{{ "Dependencies" | tr }} ({{ depends_count }})</h3>
|
||||||
<ul id="pkgdepslist">
|
<ul id="pkgdepslist">
|
||||||
{% for dep in dependencies %}
|
{% for dep in dependencies %}
|
||||||
{# Collect provides for `dep`. #}
|
{# Collect provides for `dep`. #}
|
||||||
|
@ -34,11 +34,18 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if not all_deps and depends_count > max_listing %}
|
||||||
|
<li>
|
||||||
|
<a href="/packages/{{ package.Name }}?{{ q | extend_query(['all_deps', '1']) | urlencode }}#pkgdeps">
|
||||||
|
{{ "Show %d more" | tr | format(depends_count - (dependencies | length)) }} {{ "dependencies" | tr }}...
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="pkgreqs" class="listing">
|
<div id="pkgreqs" class="listing">
|
||||||
<h3>{{ "Required by" | tr }} ({{ required_by | length }})</h3>
|
<h3>{{ "Required by" | tr }} ({{ reqs_count }})</h3>
|
||||||
<ul id="pkgreqslist">
|
<ul id="pkgreqslist">
|
||||||
{% for dep in required_by %}
|
{% for dep in required_by %}
|
||||||
<li>
|
<li>
|
||||||
|
@ -55,6 +62,11 @@
|
||||||
<em>{{ dep | dep_extra }}</em>
|
<em>{{ dep | dep_extra }}</em>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if not all_reqs and (required_by | length) > max_listing %}
|
||||||
|
<a href="/packages/{{ name }}?{{ q | extend_query(['all_reqs', '1']) | urlencode }}#pkgreqs">
|
||||||
|
{{ "Show %d more" | tr | format(reqs_count - (required_by | length)) }}...
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -276,6 +276,51 @@ def test_package(client: TestClient, package: Package):
|
||||||
assert conflicts[0].text.strip() == ", ".join(expected)
|
assert conflicts[0].text.strip() == ", ".join(expected)
|
||||||
|
|
||||||
|
|
||||||
|
def paged_depends_required(client: TestClient, package: Package):
|
||||||
|
maint = package.PackageBase.Maintainer
|
||||||
|
new_pkgs = []
|
||||||
|
|
||||||
|
with db.begin():
|
||||||
|
# Create 25 new packages that'll be used to depend on our package.
|
||||||
|
for i in range(26):
|
||||||
|
base = db.create(PackageBase, Name=f"new_pkg{i}", Maintainer=maint)
|
||||||
|
new_pkgs.append(db.create(Package, Name=base.Name))
|
||||||
|
|
||||||
|
# Create 25 deps.
|
||||||
|
for i in range(25):
|
||||||
|
create_package_dep(package, f"dep_{i}")
|
||||||
|
|
||||||
|
with db.begin():
|
||||||
|
# Create depends on this package so we get some required by listings.
|
||||||
|
for new_pkg in new_pkgs:
|
||||||
|
create_package_dep(new_pkg, package.Name)
|
||||||
|
|
||||||
|
with client as request:
|
||||||
|
resp = request.get(package_endpoint(package))
|
||||||
|
assert resp.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
# Test depends show link.
|
||||||
|
assert "Show 5 more" in resp.text
|
||||||
|
|
||||||
|
# Test required by show more link, we added 26 packages.
|
||||||
|
assert "Show 6 more" in resp.text
|
||||||
|
|
||||||
|
# Follow both links at the same time.
|
||||||
|
with client as request:
|
||||||
|
resp = request.get(
|
||||||
|
package_endpoint(package),
|
||||||
|
params={
|
||||||
|
"all_deps": True,
|
||||||
|
"all_reqs": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert resp.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
# We're should see everything and have no link.
|
||||||
|
assert "Show 5 more" not in resp.text
|
||||||
|
assert "Show 6 more" not in resp.text
|
||||||
|
|
||||||
|
|
||||||
def test_package_comments(client: TestClient, user: User, package: Package):
|
def test_package_comments(client: TestClient, user: User, package: Package):
|
||||||
now = (time.utcnow())
|
now = (time.utcnow())
|
||||||
with db.begin():
|
with db.begin():
|
||||||
|
|
Loading…
Add table
Reference in a new issue