-
- {{ "There are three types of requests that can be filed in the %sPackage Actions%s box on the package details page:"
- | tr
- | format("", "")
- | safe
- }}
-
-
- - {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
- - {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
- - {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}
-
-
- {{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests."
- | tr
- | format('', "")
- | safe
- }}
-
+
+
+ {% include 'home.html' %}
+
-
{% trans %}Submitting Packages{% endtrans %}
-
-
- {{ "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting packages%s section of the Arch User Repository ArchWiki page for more details."
- | tr
- | format('', "")
- | safe
- }}
-
- {% if ssh_fingerprints %}
-
- {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %}
-
-
- {% for keytype in ssh_fingerprints %}
- {{ keytype }}
: {{ ssh_fingerprints[keytype] }}
- {% endfor %}
-
- {% endif %}
+
+ {% include 'partials/packages/widgets/search.html' %}
+ {% include 'partials/packages/widgets/updates.html' %}
+ {% include 'partials/packages/widgets/statistics.html' %}
-
{% trans %}Discussion{% endtrans %}
-
-
- {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list."
- | tr
- | format('', "",
- '', "")
- | safe
- }}
-
-
-
{% trans %}Bug Reporting{% endtrans %}
-
-
- {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page."
- | tr
- | format('', "",
- "", "")
- | safe
- }}
-
-
-
-
-
-
-
-
-
{% endblock %}
diff --git a/templates/partials/packages/widgets/search.html b/templates/partials/packages/widgets/search.html
new file mode 100644
index 00000000..106b93ea
--- /dev/null
+++ b/templates/partials/packages/widgets/search.html
@@ -0,0 +1,14 @@
+
+
+
diff --git a/templates/partials/packages/widgets/statistics.html b/templates/partials/packages/widgets/statistics.html
new file mode 100644
index 00000000..f841ae0e
--- /dev/null
+++ b/templates/partials/packages/widgets/statistics.html
@@ -0,0 +1,55 @@
+
+
+{% if request.user.is_authenticated() %}
+
+ {% include 'partials/widgets/statistics.html' %}
+{% endif %}
diff --git a/templates/partials/packages/widgets/updates.html b/templates/partials/packages/widgets/updates.html
new file mode 100644
index 00000000..3ee1b98e
--- /dev/null
+++ b/templates/partials/packages/widgets/updates.html
@@ -0,0 +1,35 @@
+
diff --git a/templates/partials/widgets/statistics.html b/templates/partials/widgets/statistics.html
new file mode 100644
index 00000000..0bf844b6
--- /dev/null
+++ b/templates/partials/widgets/statistics.html
@@ -0,0 +1,27 @@
+
diff --git a/test/test_homepage.py b/test/test_homepage.py
index 23d7185f..a629b98c 100644
--- a/test/test_homepage.py
+++ b/test/test_homepage.py
@@ -1,13 +1,82 @@
+import re
+
+from datetime import datetime
from http import HTTPStatus
from unittest.mock import patch
+import pytest
+
from fastapi.testclient import TestClient
+from aurweb import db
from aurweb.asgi import app
+from aurweb.models.account_type import USER_ID
+from aurweb.models.package import Package
+from aurweb.models.package_base import PackageBase
+from aurweb.models.user import User
+from aurweb.redis import redis_connection
+from aurweb.testing import setup_test_db
+from aurweb.testing.html import parse_root
client = TestClient(app)
+@pytest.fixture(autouse=True)
+def setup():
+ yield setup_test_db(
+ User.__tablename__,
+ Package.__tablename__,
+ PackageBase.__tablename__
+ )
+
+
+@pytest.fixture
+def user():
+ yield db.create(User, Username="test", Email="test@example.org",
+ Passwd="testPassword", AccountTypeID=USER_ID)
+
+
+@pytest.fixture
+def redis():
+ redis = redis_connection()
+
+ def delete_keys():
+ # Cleanup keys if they exist.
+ for key in ("package_count", "orphan_count", "user_count",
+ "trusted_user_count", "seven_days_old_added",
+ "seven_days_old_updated", "year_old_updated",
+ "never_updated", "package_updates"):
+ if redis.get(key) is not None:
+ redis.delete(key)
+
+ delete_keys()
+ yield redis
+ delete_keys()
+
+
+@pytest.fixture
+def packages(user):
+ """ Yield a list of num_packages Package objects maintained by user. """
+ num_packages = 50 # Tunable
+
+ # For i..num_packages, create a package named pkg_{i}.
+ pkgs = []
+ now = int(datetime.utcnow().timestamp())
+ for i in range(num_packages):
+ pkgbase = db.create(PackageBase, Name=f"pkg_{i}",
+ Maintainer=user, Packager=user,
+ autocommit=False, SubmittedTS=now,
+ ModifiedTS=now)
+ pkg = db.create(Package, PackageBase=pkgbase,
+ Name=pkgbase.Name, autocommit=False)
+ pkgs.append(pkg)
+ now += 1
+
+ db.commit()
+
+ yield pkgs
+
+
def test_homepage():
with client as request:
response = request.get("/")
@@ -34,3 +103,49 @@ def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock):
response = request.get("/")
assert 'The following SSH fingerprints are used for the AUR' not in response.content.decode()
+
+
+def test_homepage_stats(redis, packages):
+ with client as request:
+ response = request.get("/")
+ assert response.status_code == int(HTTPStatus.OK)
+
+ root = parse_root(response.text)
+
+ expectations = [
+ ("Packages", r'\d+'),
+ ("Orphan Packages", r'\d+'),
+ ("Packages added in the past 7 days", r'\d+'),
+ ("Packages updated in the past 7 days", r'\d+'),
+ ("Packages updated in the past year", r'\d+'),
+ ("Packages never updated", r'\d+'),
+ ("Registered Users", r'\d+'),
+ ("Trusted Users", r'\d+')
+ ]
+
+ stats = root.xpath('//div[@id="pkg-stats"]//tr')
+ for i, expected in enumerate(expectations):
+ expected_key, expected_regex = expected
+ key, value = stats[i].xpath('./td')
+ assert key.text.strip() == expected_key
+ assert re.match(expected_regex, value.text.strip())
+
+
+def test_homepage_updates(redis, packages):
+ with client as request:
+ response = request.get("/")
+ assert response.status_code == int(HTTPStatus.OK)
+ # Run the request a second time to exercise the Redis path.
+ response = request.get("/")
+ assert response.status_code == int(HTTPStatus.OK)
+
+ root = parse_root(response.text)
+
+ # We expect to see the latest 15 packages, which happens to be
+ # pkg_49 .. pkg_34. So, create a list of expectations using a range
+ # starting at 49, stepping down to 49 - 15, -1 step at a time.
+ expectations = [f"pkg_{i}" for i in range(50 - 1, 50 - 1 - 15, -1)]
+ updates = root.xpath('//div[@id="pkg-updates"]/table/tbody/tr')
+ for i, expected in enumerate(expectations):
+ pkgname = updates[i].xpath('./td/a').pop(0)
+ assert pkgname.text.strip() == expected
diff --git a/test/test_packages_util.py b/test/test_packages_util.py
index 17978490..bc6a941c 100644
--- a/test/test_packages_util.py
+++ b/test/test_packages_util.py
@@ -9,6 +9,7 @@ from aurweb.models.package import Package
from aurweb.models.package_base import PackageBase
from aurweb.models.user import User
from aurweb.packages import util
+from aurweb.redis import kill_redis
from aurweb.testing import setup_test_db
@@ -33,7 +34,8 @@ def maintainer() -> User:
@pytest.fixture
def package(maintainer: User) -> Package:
- pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=maintainer)
+ pkgbase = db.create(PackageBase, Name="test-pkg",
+ Packager=maintainer, Maintainer=maintainer)
yield db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
@@ -49,3 +51,18 @@ def test_package_link(client: TestClient, maintainer: User, package: Package):
Provides=package.Name)
expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}"
assert util.package_link(package) == expected
+
+
+def test_updated_packages(maintainer: User, package: Package):
+ expected = {
+ "Name": package.Name,
+ "Version": package.Version,
+ "PackageBase": {
+ "ModifiedTS": package.PackageBase.ModifiedTS
+ }
+ }
+
+ kill_redis() # Kill it here to ensure we're on a fake instance.
+ assert util.updated_packages(1, 0) == [expected]
+ assert util.updated_packages(1, 600) == [expected]
+ kill_redis() # Kill it again, in case other tests use a real instance.