mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
[FastAPI] Modularize homepage and add side panel
This puts one more toward completion of the homepage overall; we'll need to still implement the authenticated user dashboard after this. Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
9e73936c4e
commit
d9cdd5faef
10 changed files with 500 additions and 102 deletions
|
@ -1,7 +1,10 @@
|
|||
from http import HTTPStatus
|
||||
from typing import List
|
||||
|
||||
import orjson
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import and_, orm
|
||||
|
||||
from aurweb import db
|
||||
from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider
|
||||
|
@ -10,6 +13,7 @@ from aurweb.models.package_base import PackageBase
|
|||
from aurweb.models.package_dependency import PackageDependency
|
||||
from aurweb.models.package_relation import PackageRelation
|
||||
from aurweb.models.relation_type import PROVIDES_ID, RelationType
|
||||
from aurweb.redis import redis_connection
|
||||
from aurweb.templates import register_filter
|
||||
|
||||
|
||||
|
@ -111,3 +115,52 @@ def get_pkgbase(name: str) -> PackageBase:
|
|||
raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND))
|
||||
|
||||
return pkgbase
|
||||
|
||||
|
||||
@register_filter("out_of_date")
|
||||
def out_of_date(packages: orm.Query) -> orm.Query:
|
||||
return packages.filter(PackageBase.OutOfDateTS.isnot(None))
|
||||
|
||||
|
||||
def updated_packages(limit: int = 0, cache_ttl: int = 600) -> List[Package]:
|
||||
""" Return a list of valid Package objects ordered by their
|
||||
ModifiedTS column in descending order from cache, after setting
|
||||
the cache when no key yet exists.
|
||||
|
||||
:param limit: Optional record limit
|
||||
:param cache_ttl: Cache expiration time (in seconds)
|
||||
:return: A list of Packages
|
||||
"""
|
||||
redis = redis_connection()
|
||||
packages = redis.get("package_updates")
|
||||
if packages:
|
||||
# If we already have a cache, deserialize it and return.
|
||||
return orjson.loads(packages)
|
||||
|
||||
query = db.query(Package).join(PackageBase).filter(
|
||||
PackageBase.PackagerUID.isnot(None)
|
||||
).order_by(
|
||||
PackageBase.ModifiedTS.desc()
|
||||
)
|
||||
|
||||
if limit:
|
||||
query = query.limit(limit)
|
||||
|
||||
packages = []
|
||||
for pkg in query:
|
||||
# For each Package returned by the query, append a dict
|
||||
# containing Package columns we're interested in.
|
||||
packages.append({
|
||||
"Name": pkg.Name,
|
||||
"Version": pkg.Version,
|
||||
"PackageBase": {
|
||||
"ModifiedTS": pkg.PackageBase.ModifiedTS
|
||||
}
|
||||
})
|
||||
|
||||
# Store the JSON serialization of the package_updates key into Redis.
|
||||
redis.set("package_updates", orjson.dumps(packages))
|
||||
redis.expire("package_updates", cache_ttl)
|
||||
|
||||
# Return the deserialized list of packages.
|
||||
return packages
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
""" AURWeb's primary routing module. Define all routes via @app.app.{get,post}
|
||||
decorators in some way; more complex routes should be defined in their
|
||||
own modules and imported here. """
|
||||
from datetime import datetime
|
||||
from http import HTTPStatus
|
||||
|
||||
from fastapi import APIRouter, Form, HTTPException, Request
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
from sqlalchemy import and_, or_
|
||||
|
||||
import aurweb.config
|
||||
|
||||
from aurweb import util
|
||||
from aurweb import db, util
|
||||
from aurweb.cache import db_count_cache
|
||||
from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID
|
||||
from aurweb.models.package_base import PackageBase
|
||||
from aurweb.models.user import User
|
||||
from aurweb.packages.util import updated_packages
|
||||
from aurweb.templates import make_context, render_template
|
||||
|
||||
router = APIRouter()
|
||||
|
@ -60,6 +67,71 @@ async def index(request: Request):
|
|||
context = make_context(request, "Home")
|
||||
context['ssh_fingerprints'] = util.get_ssh_fingerprints()
|
||||
|
||||
bases = db.query(PackageBase)
|
||||
|
||||
redis = aurweb.redis.redis_connection()
|
||||
stats_expire = 300 # Five minutes.
|
||||
updates_expire = 600 # Ten minutes.
|
||||
|
||||
# Package statistics.
|
||||
query = bases.filter(PackageBase.PackagerUID.isnot(None))
|
||||
context["package_count"] = await db_count_cache(
|
||||
redis, "package_count", query, expire=stats_expire)
|
||||
|
||||
query = bases.filter(
|
||||
and_(PackageBase.MaintainerUID.is_(None),
|
||||
PackageBase.PackagerUID.isnot(None))
|
||||
)
|
||||
context["orphan_count"] = await db_count_cache(
|
||||
redis, "orphan_count", query, expire=stats_expire)
|
||||
|
||||
query = db.query(User)
|
||||
context["user_count"] = await db_count_cache(
|
||||
redis, "user_count", query, expire=stats_expire)
|
||||
|
||||
query = query.filter(
|
||||
or_(User.AccountTypeID == TRUSTED_USER_ID,
|
||||
User.AccountTypeID == TRUSTED_USER_AND_DEV_ID))
|
||||
context["trusted_user_count"] = await db_count_cache(
|
||||
redis, "trusted_user_count", query, expire=stats_expire)
|
||||
|
||||
# Current timestamp.
|
||||
now = int(datetime.utcnow().timestamp())
|
||||
|
||||
seven_days = 86400 * 7 # Seven days worth of seconds.
|
||||
seven_days_ago = now - seven_days
|
||||
|
||||
one_hour = 3600
|
||||
updated = bases.filter(
|
||||
and_(PackageBase.ModifiedTS - PackageBase.SubmittedTS >= one_hour,
|
||||
PackageBase.PackagerUID.isnot(None))
|
||||
)
|
||||
|
||||
query = bases.filter(
|
||||
and_(PackageBase.SubmittedTS >= seven_days_ago,
|
||||
PackageBase.PackagerUID.isnot(None))
|
||||
)
|
||||
context["seven_days_old_added"] = await db_count_cache(
|
||||
redis, "seven_days_old_added", query, expire=stats_expire)
|
||||
|
||||
query = updated.filter(PackageBase.ModifiedTS >= seven_days_ago)
|
||||
context["seven_days_old_updated"] = await db_count_cache(
|
||||
redis, "seven_days_old_updated", query, expire=stats_expire)
|
||||
|
||||
year = seven_days * 52 # Fifty two weeks worth: one year.
|
||||
year_ago = now - year
|
||||
query = updated.filter(PackageBase.ModifiedTS >= year_ago)
|
||||
context["year_old_updated"] = await db_count_cache(
|
||||
redis, "year_old_updated", query, expire=stats_expire)
|
||||
|
||||
query = bases.filter(
|
||||
PackageBase.ModifiedTS - PackageBase.SubmittedTS < 3600)
|
||||
context["never_updated"] = await db_count_cache(
|
||||
redis, "never_updated", query, expire=stats_expire)
|
||||
|
||||
# Get the 15 most recently updated packages.
|
||||
context["package_updates"] = updated_packages(15, updates_expire)
|
||||
|
||||
return render_template(request, "index.html", context)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue