This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new 0abfa18  Allow public routes to receive committer information
0abfa18 is described below

commit 0abfa18c28286414a76dc3a2a631f8108d514341
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Sep 15 16:50:32 2025 +0100

    Allow public routes to receive committer information
---
 atr/routes/__init__.py   | 12 +++++++-----
 atr/routes/committees.py |  4 ++--
 atr/routes/download.py   | 24 ++++++++++++++++--------
 atr/routes/projects.py   |  2 +-
 atr/routes/release.py    | 12 ++++++++----
 atr/routes/root.py       |  4 ++--
 6 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/atr/routes/__init__.py b/atr/routes/__init__.py
index 4f628de..ab7bac1 100644
--- a/atr/routes/__init__.py
+++ b/atr/routes/__init__.py
@@ -21,7 +21,7 @@ import asyncio
 import functools
 import logging
 import time
-from typing import TYPE_CHECKING, Any, Final, NoReturn, ParamSpec, Protocol, 
TypeVar
+from typing import TYPE_CHECKING, Any, Concatenate, Final, NoReturn, 
ParamSpec, Protocol, TypeVar
 
 import aiofiles
 import aiofiles.os
@@ -483,12 +483,14 @@ async def get_form(request: quart.Request) -> 
datastructures.MultiDict:
 
 def public(
     path: str, methods: list[str] | None = None, measure_performance: bool = 
True
-) -> Callable[[RouteHandler[R]], RouteHandler[R]]:
+) -> Callable[[Callable[Concatenate[CommitterSession | None, P], 
Awaitable[R]]], RouteHandler[R]]:
     """Decorator for public GET routes that provides an enhanced session 
object."""
 
-    def decorator(func: RouteHandler[R]) -> RouteHandler[R]:
-        async def wrapper(*args: Any, **kwargs: Any) -> R:
-            return await func(*args, **kwargs)
+    def decorator(func: Callable[Concatenate[CommitterSession | None, P], 
Awaitable[R]]) -> RouteHandler[R]:
+        async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
+            web_session = await session.read()
+            enhanced_session = CommitterSession(web_session) if web_session 
else None
+            return await func(enhanced_session, *args, **kwargs)
 
         # Generate a unique endpoint name
         endpoint = func.__module__ + "_" + func.__name__
diff --git a/atr/routes/committees.py b/atr/routes/committees.py
index 31463a4..1008d63 100644
--- a/atr/routes/committees.py
+++ b/atr/routes/committees.py
@@ -33,7 +33,7 @@ class UpdateCommitteeKeysForm(forms.Typed):
 
 
 @routes.public("/committees")
-async def directory() -> str:
+async def directory(session: routes.CommitterSession | None) -> str:
     """Main committee directory page."""
     async with db.session() as data:
         committees = await 
data.committee(_projects=True).order_by(sql.Committee.name).all()
@@ -45,7 +45,7 @@ async def directory() -> str:
 
 
 @routes.public("/committees/<name>")
-async def view(name: str) -> str:
+async def view(session: routes.CommitterSession | None, name: str) -> str:
     # TODO: Could also import this from keys.py
     async with db.session() as data:
         committee = await data.committee(
diff --git a/atr/routes/download.py b/atr/routes/download.py
index efbc526..b1d9b25 100644
--- a/atr/routes/download.py
+++ b/atr/routes/download.py
@@ -65,19 +65,25 @@ async def all_selected(
 
 
 @routes.public("/download/path/<project_name>/<version_name>/<path:file_path>")
-async def path(project_name: str, version_name: str, file_path: str) -> 
response.Response | quart.Response:
+async def path(
+    session: routes.CommitterSession | None, project_name: str, version_name: 
str, file_path: str
+) -> response.Response | quart.Response:
     """Download a file or list a directory from a release in any phase."""
     return await _download_or_list(project_name, version_name, file_path)
 
 
 @routes.public("/download/path/<project_name>/<version_name>/")
-async def path_empty(project_name: str, version_name: str) -> 
response.Response | quart.Response:
+async def path_empty(
+    session: routes.CommitterSession | None, project_name: str, version_name: 
str
+) -> response.Response | quart.Response:
     """List files at the root of a release directory for download."""
     return await _download_or_list(project_name, version_name, ".")
 
 
 @routes.public("/download/sh/<project_name>/<version_name>")
-async def sh_selected(project_name: str, version_name: str) -> 
response.Response | quart.Response:
+async def sh_selected(
+    session: routes.CommitterSession | None, project_name: str, version_name: 
str
+) -> response.Response | quart.Response:
     """Shell script to download a release."""
     conf = config.get()
     app_host = conf.APP_HOST
@@ -92,10 +98,12 @@ async def sh_selected(project_name: str, version_name: str) 
-> response.Response
 
 
 @routes.public("/download/urls/<project_name>/<version_name>")
-async def urls_selected(project_name: str, version_name: str) -> 
response.Response | quart.Response:
+async def urls_selected(
+    session: routes.CommitterSession | None, project_name: str, version_name: 
str
+) -> response.Response | quart.Response:
     try:
-        async with db.session() as session:
-            release = await session.release(project_name=project_name, 
version=version_name).demand(
+        async with db.session() as data:
+            release = await data.release(project_name=project_name, 
version=version_name).demand(
                 ValueError("Release not found")
             )
         url_list_str = await _generate_file_url_list(release)
@@ -149,8 +157,8 @@ async def _download_or_list(project_name: str, 
version_name: str, file_path: str
         raise routes.FlashError("Path must be relative")
 
     # We allow downloading files from any phase
-    async with db.session() as session:
-        release = await session.release(project_name=project_name, 
version=version_name).demand(
+    async with db.session() as data:
+        release = await data.release(project_name=project_name, 
version=version_name).demand(
             base.ASFQuartException("Release does not exist", errorcode=404)
         )
     full_path = util.release_directory(release) / file_path
diff --git a/atr/routes/projects.py b/atr/routes/projects.py
index 7f9253a..6217591 100644
--- a/atr/routes/projects.py
+++ b/atr/routes/projects.py
@@ -277,7 +277,7 @@ async def delete(session: routes.CommitterSession) -> 
response.Response:
 
 
 @routes.public("/projects")
-async def projects() -> str:
+async def projects(session: routes.CommitterSession | None) -> str:
     """Main project directory page."""
     async with db.session() as data:
         projects = await 
data.project(_committee=True).order_by(sql.Project.full_name).all()
diff --git a/atr/routes/release.py b/atr/routes/release.py
index 6cb9af4..0b90a7b 100644
--- a/atr/routes/release.py
+++ b/atr/routes/release.py
@@ -35,7 +35,7 @@ if asfquart.APP is ...:
 
 
 @routes.public("/releases/finished/<project_name>")
-async def finished(project_name: str) -> str:
+async def finished(session: routes.CommitterSession | None, project_name: str) 
-> str:
     """View all finished releases for a project."""
     async with db.session() as data:
         project = await data.project(name=project_name, 
status=sql.ProjectStatus.ACTIVE).demand(
@@ -59,7 +59,7 @@ async def finished(project_name: str) -> str:
 
 
 @routes.public("/releases")
-async def releases() -> str:
+async def releases(session: routes.CommitterSession | None) -> str:
     """View all releases."""
     # Releases are public, so we don't need to filter by user
     async with db.session() as data:
@@ -99,7 +99,9 @@ async def select(session: routes.CommitterSession, 
project_name: str) -> str:
 
 
 @routes.public("/release/view/<project_name>/<version_name>")
-async def view(project_name: str, version_name: str) -> response.Response | 
str:
+async def view(
+    session: routes.CommitterSession | None, project_name: str, version_name: 
str
+) -> response.Response | str:
     """View all the files in the rsync upload directory for a release."""
     async with db.session() as data:
         release_name = sql.release_name(project_name, version_name)
@@ -126,7 +128,9 @@ async def view(project_name: str, version_name: str) -> 
response.Response | str:
 
 
 @routes.public("/release/view/<project_name>/<version_name>/<path:file_path>")
-async def view_path(project_name: str, version_name: str, file_path: str) -> 
response.Response | str:
+async def view_path(
+    session: routes.CommitterSession | None, project_name: str, version_name: 
str, file_path: str
+) -> response.Response | str:
     """View the content of a specific file in the final release."""
     async with db.session() as data:
         release_name = sql.release_name(project_name, version_name)
diff --git a/atr/routes/root.py b/atr/routes/root.py
index 816e995..60f160e 100644
--- a/atr/routes/root.py
+++ b/atr/routes/root.py
@@ -71,7 +71,7 @@ async def about(session: routes.CommitterSession) -> str:
 
 
 @routes.public("/")
-async def index() -> response.Response | str:
+async def index(session: routes.CommitterSession | None) -> response.Response 
| str:
     """Show public info or an entry portal for participants."""
     session_data = await asfquart.session.read()
     if session_data:
@@ -146,7 +146,7 @@ async def index() -> response.Response | str:
 
 
 @routes.public("/policies")
-async def policies() -> str:
+async def policies(session: routes.CommitterSession | None) -> str:
     return await template.blank("Policies", content=_POLICIES)
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to